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 This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include "UefiShellCommandLib.h"
20 // STATIC local variables
21 STATIC SHELL_COMMAND_INTERNAL_LIST_ENTRY mCommandList
;
22 STATIC SCRIPT_FILE_LIST mScriptList
;
23 STATIC ALIAS_LIST mAliasList
;
24 STATIC BOOLEAN mEchoState
;
25 STATIC BOOLEAN mExitRequested
;
26 STATIC UINT64 mExitCode
;
27 STATIC BOOLEAN mExitScript
;
28 STATIC CHAR16
*mProfileList
;
29 STATIC UINTN mProfileListSize
;
30 STATIC UINTN mFsMaxCount
= 0;
31 STATIC UINTN mBlkMaxCount
= 0;
32 STATIC BUFFER_LIST mFileHandleList
;
34 STATIC CONST CHAR8 Hex
[] = {
53 // global variables required by library class.
54 EFI_UNICODE_COLLATION_PROTOCOL
*gUnicodeCollation
= NULL
;
55 SHELL_MAP_LIST gShellMapList
;
56 SHELL_MAP_LIST
*gShellCurMapping
= NULL
;
58 CONST CHAR16
* SupportLevel
[] = {
66 Function to make sure that the global protocol pointers are valid.
67 must be called after constructor before accessing the pointers.
77 EFI_UNICODE_COLLATION_PROTOCOL
*Uc
;
83 GetEfiGlobalVariable2 (EFI_PLATFORM_LANG_VARIABLE_NAME
, (VOID
**)&PlatformLang
, NULL
);
84 if (PlatformLang
== NULL
) {
85 return EFI_UNSUPPORTED
;
88 if (gUnicodeCollation
== NULL
) {
89 Status
= gBS
->LocateHandleBuffer (
91 &gEfiUnicodeCollation2ProtocolGuid
,
96 if (EFI_ERROR (Status
)) {
100 for (Index
= 0; Index
< NumHandles
; Index
++) {
102 // Open Unicode Collation Protocol
104 Status
= gBS
->OpenProtocol (
106 &gEfiUnicodeCollation2ProtocolGuid
,
110 EFI_OPEN_PROTOCOL_GET_PROTOCOL
112 if (EFI_ERROR (Status
)) {
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 FreePool (PlatformLang
);
138 return (gUnicodeCollation
== NULL
) ? EFI_UNSUPPORTED
: EFI_SUCCESS
;
142 Constructor for the Shell Command library.
144 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
146 @param ImageHandle the image handle of the process
147 @param SystemTable the EFI System Table pointer
149 @retval EFI_SUCCESS the initialization was complete sucessfully
153 ShellCommandLibConstructor (
154 IN EFI_HANDLE ImageHandle
,
155 IN EFI_SYSTEM_TABLE
*SystemTable
159 InitializeListHead(&gShellMapList
.Link
);
160 InitializeListHead(&mCommandList
.Link
);
161 InitializeListHead(&mAliasList
.Link
);
162 InitializeListHead(&mScriptList
.Link
);
163 InitializeListHead(&mFileHandleList
.Link
);
166 mExitRequested
= FALSE
;
168 mProfileListSize
= 0;
171 Status
= CommandInit ();
172 if (EFI_ERROR (Status
)) {
173 return EFI_DEVICE_ERROR
;
176 return (RETURN_SUCCESS
);
180 Frees list of file handles.
182 @param[in] List The list to free.
189 BUFFER_LIST
*BufferListEntry
;
195 // enumerate through the buffer list and free all memory
197 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
198 ; !IsListEmpty (&List
->Link
)
199 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
201 RemoveEntryList(&BufferListEntry
->Link
);
202 ASSERT(BufferListEntry
->Buffer
!= NULL
);
203 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)(BufferListEntry
->Buffer
))->Path
);
204 SHELL_FREE_NON_NULL(BufferListEntry
->Buffer
);
205 SHELL_FREE_NON_NULL(BufferListEntry
);
210 Destructor for the library. free any resources.
212 @param ImageHandle the image handle of the process
213 @param SystemTable the EFI System Table pointer
215 @retval RETURN_SUCCESS this function always returns success
219 ShellCommandLibDestructor (
220 IN EFI_HANDLE ImageHandle
,
221 IN EFI_SYSTEM_TABLE
*SystemTable
224 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
226 SCRIPT_FILE_LIST
*Node3
;
227 SHELL_MAP_LIST
*MapNode
;
229 // enumerate throught the list and free all the memory
231 while (!IsListEmpty (&mCommandList
.Link
)) {
232 Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
);
233 RemoveEntryList(&Node
->Link
);
234 SHELL_FREE_NON_NULL(Node
->CommandString
);
236 DEBUG_CODE(Node
= NULL
;);
240 // enumerate through the alias list and free all memory
242 while (!IsListEmpty (&mAliasList
.Link
)) {
243 Node2
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
);
244 RemoveEntryList(&Node2
->Link
);
245 SHELL_FREE_NON_NULL(Node2
->CommandString
);
246 SHELL_FREE_NON_NULL(Node2
->Alias
);
247 SHELL_FREE_NON_NULL(Node2
);
248 DEBUG_CODE(Node2
= NULL
;);
252 // enumerate throught the list and free all the memory
254 while (!IsListEmpty (&mScriptList
.Link
)) {
255 Node3
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
256 RemoveEntryList(&Node3
->Link
);
257 DeleteScriptFileStruct(Node3
->Data
);
262 // enumerate throught the mappings list and free all the memory
264 if (!IsListEmpty(&gShellMapList
.Link
)) {
265 for (MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
266 ; !IsListEmpty (&gShellMapList
.Link
)
267 ; MapNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
269 ASSERT(MapNode
!= NULL
);
270 RemoveEntryList(&MapNode
->Link
);
271 SHELL_FREE_NON_NULL(MapNode
->DevicePath
);
272 SHELL_FREE_NON_NULL(MapNode
->MapName
);
273 SHELL_FREE_NON_NULL(MapNode
->CurrentDirectoryPath
);
277 if (!IsListEmpty(&mFileHandleList
.Link
)){
278 FreeFileHandleList(&mFileHandleList
);
281 if (mProfileList
!= NULL
) {
282 FreePool(mProfileList
);
285 gUnicodeCollation
= NULL
;
286 gShellCurMapping
= NULL
;
288 return (RETURN_SUCCESS
);
292 Find a dynamic command protocol instance given a command name string.
294 @param CommandString the command name string
296 @return instance the command protocol instance, if dynamic command instance found
297 @retval NULL no dynamic command protocol instance found for name
299 CONST EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*
300 ShellCommandFindDynamicCommand (
301 IN CONST CHAR16
*CommandString
305 EFI_HANDLE
*CommandHandleList
;
306 EFI_HANDLE
*NextCommand
;
307 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
309 CommandHandleList
= GetHandleListByProtocol(&gEfiShellDynamicCommandProtocolGuid
);
310 if (CommandHandleList
== NULL
) {
312 // not found or out of resources
317 for (NextCommand
= CommandHandleList
; *NextCommand
!= NULL
; NextCommand
++) {
318 Status
= gBS
->HandleProtocol(
320 &gEfiShellDynamicCommandProtocolGuid
,
321 (VOID
**)&DynamicCommand
324 if (EFI_ERROR(Status
)) {
328 if (gUnicodeCollation
->StriColl(
330 (CHAR16
*)CommandString
,
331 (CHAR16
*)DynamicCommand
->CommandName
) == 0
333 FreePool(CommandHandleList
);
334 return (DynamicCommand
);
338 FreePool(CommandHandleList
);
343 Checks if a command exists as a dynamic command protocol instance
345 @param[in] CommandString The command string to check for on the list.
348 ShellCommandDynamicCommandExists (
349 IN CONST CHAR16
*CommandString
352 return (BOOLEAN
) ((ShellCommandFindDynamicCommand(CommandString
) != NULL
));
356 Checks if a command is already on the internal command list.
358 @param[in] CommandString The command string to check for on the list.
361 ShellCommandIsCommandOnInternalList(
362 IN CONST CHAR16
*CommandString
365 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
368 // assert for NULL parameter
370 ASSERT(CommandString
!= NULL
);
373 // check for the command
375 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
376 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
377 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
379 ASSERT(Node
->CommandString
!= NULL
);
380 if (gUnicodeCollation
->StriColl(
382 (CHAR16
*)CommandString
,
383 Node
->CommandString
) == 0
392 Checks if a command exists, either internally or through the dynamic command protocol.
394 @param[in] CommandString The command string to check for on the list.
398 ShellCommandIsCommandOnList(
399 IN CONST CHAR16
*CommandString
402 if (ShellCommandIsCommandOnInternalList(CommandString
)) {
406 return ShellCommandDynamicCommandExists(CommandString
);
410 Get the help text for a dynamic command.
412 @param[in] CommandString The command name.
414 @retval NULL No help text was found.
415 @return String of help text. Caller required to free.
418 ShellCommandGetDynamicCommandHelp(
419 IN CONST CHAR16
*CommandString
422 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
424 DynamicCommand
= (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*)ShellCommandFindDynamicCommand(CommandString
);
425 if (DynamicCommand
== NULL
) {
430 // TODO: how to get proper language?
432 return DynamicCommand
->GetHelp(DynamicCommand
, "en");
436 Get the help text for an internal command.
438 @param[in] CommandString The command name.
440 @retval NULL No help text was found.
441 @return String of help text. Caller reuiqred to free.
444 ShellCommandGetInternalCommandHelp(
445 IN CONST CHAR16
*CommandString
448 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
451 // assert for NULL parameter
453 ASSERT(CommandString
!= NULL
);
456 // check for the command
458 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
459 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
460 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
462 ASSERT(Node
->CommandString
!= NULL
);
463 if (gUnicodeCollation
->StriColl(
465 (CHAR16
*)CommandString
,
466 Node
->CommandString
) == 0
468 return (HiiGetString(Node
->HiiHandle
, Node
->ManFormatHelp
, NULL
));
475 Get the help text for a command.
477 @param[in] CommandString The command name.
479 @retval NULL No help text was found.
480 @return String of help text.Caller reuiqred to free.
484 ShellCommandGetCommandHelp (
485 IN CONST CHAR16
*CommandString
489 HelpStr
= ShellCommandGetInternalCommandHelp(CommandString
);
491 if (HelpStr
== NULL
) {
492 HelpStr
= ShellCommandGetDynamicCommandHelp(CommandString
);
500 Registers handlers of type SHELL_RUN_COMMAND and
501 SHELL_GET_MAN_FILENAME for each shell command.
503 If the ShellSupportLevel is greater than the value of the
504 PcdShellSupportLevel then return RETURN_UNSUPPORTED.
506 Registers the handlers specified by GetHelpInfoHandler and CommandHandler
507 with the command specified by CommandString. If the command named by
508 CommandString has already been registered, then return
509 RETURN_ALREADY_STARTED.
511 If there are not enough resources available to register the handlers then
512 RETURN_OUT_OF_RESOURCES is returned.
514 If CommandString is NULL, then ASSERT().
515 If GetHelpInfoHandler is NULL, then ASSERT().
516 If CommandHandler is NULL, then ASSERT().
517 If ProfileName is NULL, then ASSERT().
519 @param[in] CommandString Pointer to the command name. This is the
520 name to look for on the command line in
522 @param[in] CommandHandler Pointer to a function that runs the
524 @param[in] GetManFileName Pointer to a function that provides man
526 @param[in] ShellMinSupportLevel minimum Shell Support Level which has this
528 @param[in] ProfileName profile name to require for support of this
530 @param[in] CanAffectLE indicates whether this command's return value
531 can change the LASTERROR environment variable.
532 @param[in] HiiHandle Handle of this command's HII entry.
533 @param[in] ManFormatHelp HII locator for the help text.
535 @retval RETURN_SUCCESS The handlers were registered.
536 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
537 register the shell command.
538 @retval RETURN_UNSUPPORTED the ShellMinSupportLevel was higher than the
539 currently allowed support level.
540 @retval RETURN_ALREADY_STARTED The CommandString represents a command that
541 is already registered. Only 1 handler set for
542 a given command is allowed.
543 @sa SHELL_GET_MAN_FILENAME
544 @sa SHELL_RUN_COMMAND
548 ShellCommandRegisterCommandName (
549 IN CONST CHAR16
*CommandString
,
550 IN SHELL_RUN_COMMAND CommandHandler
,
551 IN SHELL_GET_MAN_FILENAME GetManFileName
,
552 IN UINT32 ShellMinSupportLevel
,
553 IN CONST CHAR16
*ProfileName
,
554 IN CONST BOOLEAN CanAffectLE
,
555 IN CONST EFI_HANDLE HiiHandle
,
556 IN CONST EFI_STRING_ID ManFormatHelp
559 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
560 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Command
;
561 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*PrevCommand
;
562 INTN LexicalMatchValue
;
565 // Initialize local variables.
569 LexicalMatchValue
= 0;
572 // ASSERTs for NULL parameters
574 ASSERT(CommandString
!= NULL
);
575 ASSERT(GetManFileName
!= NULL
);
576 ASSERT(CommandHandler
!= NULL
);
577 ASSERT(ProfileName
!= NULL
);
580 // check for shell support level
582 if (PcdGet8(PcdShellSupportLevel
) < ShellMinSupportLevel
) {
583 return (RETURN_UNSUPPORTED
);
587 // check for already on the list
589 if (ShellCommandIsCommandOnList(CommandString
)) {
590 return (RETURN_ALREADY_STARTED
);
594 // allocate memory for new struct
596 Node
= AllocateZeroPool(sizeof(SHELL_COMMAND_INTERNAL_LIST_ENTRY
));
598 return RETURN_OUT_OF_RESOURCES
;
600 Node
->CommandString
= AllocateCopyPool(StrSize(CommandString
), CommandString
);
601 if (Node
->CommandString
== NULL
) {
603 return RETURN_OUT_OF_RESOURCES
;
606 Node
->GetManFileName
= GetManFileName
;
607 Node
->CommandHandler
= CommandHandler
;
608 Node
->LastError
= CanAffectLE
;
609 Node
->HiiHandle
= HiiHandle
;
610 Node
->ManFormatHelp
= ManFormatHelp
;
612 if ( StrLen(ProfileName
)>0
613 && ((mProfileList
!= NULL
614 && StrStr(mProfileList
, ProfileName
) == NULL
) || mProfileList
== NULL
)
616 ASSERT((mProfileList
== NULL
&& mProfileListSize
== 0) || (mProfileList
!= NULL
));
617 if (mProfileList
== NULL
) {
619 // If this is the first make a leading ';'
621 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
623 StrnCatGrow(&mProfileList
, &mProfileListSize
, ProfileName
, 0);
624 StrnCatGrow(&mProfileList
, &mProfileListSize
, L
";", 0);
628 // Insert a new entry on top of the list
630 InsertHeadList (&mCommandList
.Link
, &Node
->Link
);
633 // Move a new registered command to its sorted ordered location in the list
635 for (Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
),
636 PrevCommand
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode (&mCommandList
.Link
)
637 ; !IsNull (&mCommandList
.Link
, &Command
->Link
)
638 ; Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode (&mCommandList
.Link
, &Command
->Link
)) {
641 // Get Lexical Comparison Value between PrevCommand and Command list entry
643 LexicalMatchValue
= gUnicodeCollation
->StriColl (
645 PrevCommand
->CommandString
,
646 Command
->CommandString
650 // Swap PrevCommand and Command list entry if PrevCommand list entry
651 // is alphabetically greater than Command list entry
653 if (LexicalMatchValue
> 0){
654 Command
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*) SwapListEntries (&PrevCommand
->Link
, &Command
->Link
);
655 } else if (LexicalMatchValue
< 0) {
657 // PrevCommand entry is lexically lower than Command entry
663 return (RETURN_SUCCESS
);
667 Function to get the current Profile string.
669 @retval NULL There are no installed profiles.
670 @return A semi-colon delimited list of profiles.
674 ShellCommandGetProfileList (
678 return (mProfileList
);
682 Checks if a command string has been registered for CommandString and if so it runs
683 the previously registered handler for that command with the command line.
685 If CommandString is NULL, then ASSERT().
687 If Sections is specified, then each section name listed will be compared in a casesensitive
688 manner, to the section names described in Appendix B UEFI Shell 2.0 spec. If the section exists,
689 it will be appended to the returned help text. If the section does not exist, no
690 information will be returned. If Sections is NULL, then all help text information
691 available will be returned.
693 @param[in] CommandString Pointer to the command name. This is the name
694 found on the command line in the shell.
695 @param[in, out] RetVal Pointer to the return vaule from the command handler.
697 @param[in, out] CanAffectLE indicates whether this command's return value
698 needs to be placed into LASTERROR environment variable.
700 @retval RETURN_SUCCESS The handler was run.
701 @retval RETURN_NOT_FOUND The CommandString did not match a registered
703 @sa SHELL_RUN_COMMAND
707 ShellCommandRunCommandHandler (
708 IN CONST CHAR16
*CommandString
,
709 IN OUT SHELL_STATUS
*RetVal
,
710 IN OUT BOOLEAN
*CanAffectLE OPTIONAL
713 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
714 EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*DynamicCommand
;
717 // assert for NULL parameters
719 ASSERT(CommandString
!= NULL
);
722 // check for the command
724 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
725 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
726 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
728 ASSERT(Node
->CommandString
!= NULL
);
729 if (gUnicodeCollation
->StriColl(
731 (CHAR16
*)CommandString
,
732 Node
->CommandString
) == 0
734 if (CanAffectLE
!= NULL
) {
735 *CanAffectLE
= Node
->LastError
;
737 if (RetVal
!= NULL
) {
738 *RetVal
= Node
->CommandHandler(NULL
, gST
);
740 Node
->CommandHandler(NULL
, gST
);
742 return (RETURN_SUCCESS
);
747 // An internal command was not found, try to find a dynamic command
749 DynamicCommand
= (EFI_SHELL_DYNAMIC_COMMAND_PROTOCOL
*)ShellCommandFindDynamicCommand(CommandString
);
750 if (DynamicCommand
!= NULL
) {
751 if (RetVal
!= NULL
) {
752 *RetVal
= DynamicCommand
->Handler(DynamicCommand
, gST
, gEfiShellParametersProtocol
, gEfiShellProtocol
);
754 DynamicCommand
->Handler(DynamicCommand
, gST
, gEfiShellParametersProtocol
, gEfiShellProtocol
);
756 return (RETURN_SUCCESS
);
759 return (RETURN_NOT_FOUND
);
763 Checks if a command string has been registered for CommandString and if so it
764 returns the MAN filename specified for that command.
766 If CommandString is NULL, then ASSERT().
768 @param[in] CommandString Pointer to the command name. This is the name
769 found on the command line in the shell.\
771 @retval NULL the commandString was not a registered command.
772 @return other the name of the MAN file.
773 @sa SHELL_GET_MAN_FILENAME
777 ShellCommandGetManFileNameHandler (
778 IN CONST CHAR16
*CommandString
781 SHELL_COMMAND_INTERNAL_LIST_ENTRY
*Node
;
784 // assert for NULL parameters
786 ASSERT(CommandString
!= NULL
);
789 // check for the command
791 for ( Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetFirstNode(&mCommandList
.Link
)
792 ; !IsNull(&mCommandList
.Link
, &Node
->Link
)
793 ; Node
= (SHELL_COMMAND_INTERNAL_LIST_ENTRY
*)GetNextNode(&mCommandList
.Link
, &Node
->Link
)
795 ASSERT(Node
->CommandString
!= NULL
);
796 if (gUnicodeCollation
->StriColl(
798 (CHAR16
*)CommandString
,
799 Node
->CommandString
) == 0
801 return (Node
->GetManFileName());
808 Get the list of all available shell internal commands. This is a linked list
809 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
810 list functions. do not modify the values.
812 @param[in] Sort TRUE to alphabetically sort the values first. FALSE otherwise.
814 @return a Linked list of all available shell commands.
818 ShellCommandGetCommandList (
819 IN CONST BOOLEAN Sort
823 // return ((COMMAND_LIST*)(&mCommandList));
825 return ((COMMAND_LIST
*)(&mCommandList
));
829 Registers aliases to be set as part of the initialization of the shell application.
831 If Command is NULL, then ASSERT().
832 If Alias is NULL, then ASSERT().
834 @param[in] Command Pointer to the Command
835 @param[in] Alias Pointer to Alias
837 @retval RETURN_SUCCESS The handlers were registered.
838 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
839 register the shell command.
843 ShellCommandRegisterAlias (
844 IN CONST CHAR16
*Command
,
845 IN CONST CHAR16
*Alias
849 ALIAS_LIST
*CommandAlias
;
850 ALIAS_LIST
*PrevCommandAlias
;
851 INTN LexicalMatchValue
;
856 ASSERT(Command
!= NULL
);
857 ASSERT(Alias
!= NULL
);
860 // allocate memory for new struct
862 Node
= AllocateZeroPool(sizeof(ALIAS_LIST
));
864 return RETURN_OUT_OF_RESOURCES
;
866 Node
->CommandString
= AllocateCopyPool(StrSize(Command
), Command
);
867 if (Node
->CommandString
== NULL
) {
869 return RETURN_OUT_OF_RESOURCES
;
871 Node
->Alias
= AllocateCopyPool(StrSize(Alias
), Alias
);
872 if (Node
->Alias
== NULL
) {
873 FreePool (Node
->CommandString
);
875 return RETURN_OUT_OF_RESOURCES
;
878 InsertHeadList (&mAliasList
.Link
, &Node
->Link
);
881 // Move a new pre-defined registered alias to its sorted ordered location in the list
883 for ( CommandAlias
= (ALIAS_LIST
*)GetFirstNode (&mAliasList
.Link
),
884 PrevCommandAlias
= (ALIAS_LIST
*)GetFirstNode (&mAliasList
.Link
)
885 ; !IsNull (&mAliasList
.Link
, &CommandAlias
->Link
)
886 ; CommandAlias
= (ALIAS_LIST
*) GetNextNode (&mAliasList
.Link
, &CommandAlias
->Link
) ) {
888 // Get Lexical comparison value between PrevCommandAlias and CommandAlias List Entry
890 LexicalMatchValue
= gUnicodeCollation
->StriColl (
892 PrevCommandAlias
->Alias
,
897 // Swap PrevCommandAlias and CommandAlias list entry if PrevCommandAlias list entry
898 // is alphabetically greater than CommandAlias list entry
900 if (LexicalMatchValue
> 0) {
901 CommandAlias
= (ALIAS_LIST
*) SwapListEntries (&PrevCommandAlias
->Link
, &CommandAlias
->Link
);
902 } else if (LexicalMatchValue
< 0) {
904 // PrevCommandAlias entry is lexically lower than CommandAlias entry
910 return (RETURN_SUCCESS
);
914 Get the list of all shell alias commands. This is a linked list
915 (via LIST_ENTRY structure). enumerate through it using the BaseLib linked
916 list functions. do not modify the values.
918 @return a Linked list of all requested shell alias'.
922 ShellCommandGetInitAliasList (
926 return (&mAliasList
);
930 Determine if a given alias is on the list of built in alias'.
932 @param[in] Alias The alias to test for
934 @retval TRUE The alias is a built in alias
935 @retval FALSE The alias is not a built in alias
939 ShellCommandIsOnAliasList(
940 IN CONST CHAR16
*Alias
946 // assert for NULL parameter
948 ASSERT(Alias
!= NULL
);
951 // check for the Alias
953 for ( Node
= (ALIAS_LIST
*)GetFirstNode(&mAliasList
.Link
)
954 ; !IsNull(&mAliasList
.Link
, &Node
->Link
)
955 ; Node
= (ALIAS_LIST
*)GetNextNode(&mAliasList
.Link
, &Node
->Link
)
957 ASSERT(Node
->CommandString
!= NULL
);
958 ASSERT(Node
->Alias
!= NULL
);
959 if (gUnicodeCollation
->StriColl(
962 Node
->CommandString
) == 0
966 if (gUnicodeCollation
->StriColl(
978 Function to determine current state of ECHO. Echo determines if lines from scripts
979 and ECHO commands are enabled.
981 @retval TRUE Echo is currently enabled
982 @retval FALSE Echo is currently disabled
986 ShellCommandGetEchoState(
994 Function to set current state of ECHO. Echo determines if lines from scripts
995 and ECHO commands are enabled.
997 If State is TRUE, Echo will be enabled.
998 If State is FALSE, Echo will be disabled.
1000 @param[in] State How to set echo.
1004 ShellCommandSetEchoState(
1012 Indicate that the current shell or script should exit.
1014 @param[in] ScriptOnly TRUE if exiting a script; FALSE otherwise.
1015 @param[in] ErrorCode The 64 bit error code to return.
1019 ShellCommandRegisterExit (
1020 IN BOOLEAN ScriptOnly
,
1021 IN CONST UINT64 ErrorCode
1024 mExitRequested
= (BOOLEAN
)(!mExitRequested
);
1025 if (mExitRequested
) {
1026 mExitScript
= ScriptOnly
;
1028 mExitScript
= FALSE
;
1030 mExitCode
= ErrorCode
;
1034 Retrieve the Exit indicator.
1036 @retval TRUE Exit was indicated.
1037 @retval FALSE Exis was not indicated.
1041 ShellCommandGetExit (
1045 return (mExitRequested
);
1049 Retrieve the Exit code.
1051 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1053 @return the value passed into RegisterExit.
1057 ShellCommandGetExitCode (
1064 Retrieve the Exit script indicator.
1066 If ShellCommandGetExit returns FALSE than the return from this is undefined.
1068 @retval TRUE ScriptOnly was indicated.
1069 @retval FALSE ScriptOnly was not indicated.
1073 ShellCommandGetScriptExit (
1077 return (mExitScript
);
1081 Function to cleanup all memory from a SCRIPT_FILE structure.
1083 @param[in] Script The pointer to the structure to cleanup.
1087 DeleteScriptFileStruct (
1088 IN SCRIPT_FILE
*Script
1093 if (Script
== NULL
) {
1097 for (LoopVar
= 0 ; LoopVar
< Script
->Argc
; LoopVar
++) {
1098 SHELL_FREE_NON_NULL(Script
->Argv
[LoopVar
]);
1100 if (Script
->Argv
!= NULL
) {
1101 SHELL_FREE_NON_NULL(Script
->Argv
);
1103 Script
->CurrentCommand
= NULL
;
1104 while (!IsListEmpty (&Script
->CommandList
)) {
1105 Script
->CurrentCommand
= (SCRIPT_COMMAND_LIST
*)GetFirstNode(&Script
->CommandList
);
1106 if (Script
->CurrentCommand
!= NULL
) {
1107 RemoveEntryList(&Script
->CurrentCommand
->Link
);
1108 if (Script
->CurrentCommand
->Cl
!= NULL
) {
1109 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Cl
);
1111 if (Script
->CurrentCommand
->Data
!= NULL
) {
1112 SHELL_FREE_NON_NULL(Script
->CurrentCommand
->Data
);
1114 SHELL_FREE_NON_NULL(Script
->CurrentCommand
);
1117 SHELL_FREE_NON_NULL(Script
->ScriptName
);
1118 SHELL_FREE_NON_NULL(Script
);
1122 Function to return a pointer to the currently running script file object.
1124 @retval NULL A script file is not currently running.
1125 @return A pointer to the current script file object.
1129 ShellCommandGetCurrentScriptFile (
1133 SCRIPT_FILE_LIST
*List
;
1134 if (IsListEmpty (&mScriptList
.Link
)) {
1137 List
= ((SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
));
1138 return (List
->Data
);
1142 Function to set a new script as the currently running one.
1144 This function will correctly stack and unstack nested scripts.
1146 @param[in] Script Pointer to new script information structure. if NULL
1147 will remove and de-allocate the top-most Script structure.
1149 @return A pointer to the current running script file after this
1150 change. NULL if removing the final script.
1154 ShellCommandSetNewScript (
1155 IN SCRIPT_FILE
*Script OPTIONAL
1158 SCRIPT_FILE_LIST
*Node
;
1159 if (Script
== NULL
) {
1160 if (IsListEmpty (&mScriptList
.Link
)) {
1163 Node
= (SCRIPT_FILE_LIST
*)GetFirstNode(&mScriptList
.Link
);
1164 RemoveEntryList(&Node
->Link
);
1165 DeleteScriptFileStruct(Node
->Data
);
1168 Node
= AllocateZeroPool(sizeof(SCRIPT_FILE_LIST
));
1172 Node
->Data
= Script
;
1173 InsertHeadList(&mScriptList
.Link
, &Node
->Link
);
1175 return (ShellCommandGetCurrentScriptFile());
1179 Function to generate the next default mapping name.
1181 If the return value is not NULL then it must be callee freed.
1183 @param Type What kind of mapping name to make.
1185 @retval NULL a memory allocation failed.
1186 @return a new map name string
1190 ShellCommandCreateNewMappingName(
1191 IN CONST SHELL_MAPPING_TYPE Type
1195 ASSERT(Type
< MappingTypeMax
);
1199 String
= AllocateZeroPool(PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]));
1202 PcdGet8(PcdShellMapNameLength
) * sizeof(String
[0]),
1203 Type
== MappingTypeFileSystem
?L
"FS%d:":L
"BLK%d:",
1204 Type
== MappingTypeFileSystem
?mFsMaxCount
++:mBlkMaxCount
++);
1210 Function to add a map node to the list of map items and update the "path" environment variable (optionally).
1212 If Path is TRUE (during initialization only), the path environment variable will also be updated to include
1213 default paths on the new map name...
1215 Path should be FALSE when this function is called from the protocol SetMap function.
1217 @param[in] Name The human readable mapped name.
1218 @param[in] DevicePath The Device Path for this map.
1219 @param[in] Flags The Flags attribute for this map item.
1220 @param[in] Path TRUE to update path, FALSE to skip this step (should only be TRUE during initialization).
1222 @retval EFI_SUCCESS The addition was sucessful.
1223 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
1224 @retval EFI_INVALID_PARAMETER A parameter was invalid.
1228 ShellCommandAddMapItemAndUpdatePath(
1229 IN CONST CHAR16
*Name
,
1230 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1231 IN CONST UINT64 Flags
,
1232 IN CONST BOOLEAN Path
1236 SHELL_MAP_LIST
*MapListNode
;
1237 CONST CHAR16
*OriginalPath
;
1243 OriginalPath
= NULL
;
1244 Status
= EFI_SUCCESS
;
1246 MapListNode
= AllocateZeroPool(sizeof(SHELL_MAP_LIST
));
1247 if (MapListNode
== NULL
) {
1248 Status
= EFI_OUT_OF_RESOURCES
;
1250 MapListNode
->Flags
= Flags
;
1251 MapListNode
->MapName
= AllocateCopyPool(StrSize(Name
), Name
);
1252 MapListNode
->DevicePath
= DuplicateDevicePath(DevicePath
);
1253 if ((MapListNode
->MapName
== NULL
) || (MapListNode
->DevicePath
== NULL
)){
1254 Status
= EFI_OUT_OF_RESOURCES
;
1256 InsertTailList(&gShellMapList
.Link
, &MapListNode
->Link
);
1259 if (EFI_ERROR(Status
)) {
1260 if (MapListNode
!= NULL
) {
1261 if (MapListNode
->DevicePath
!= NULL
) {
1262 FreePool(MapListNode
->DevicePath
);
1264 if (MapListNode
->MapName
!= NULL
) {
1265 FreePool(MapListNode
->MapName
);
1267 FreePool(MapListNode
);
1271 // Since there was no error and Path was TRUE
1272 // Now add the correct path for that mapping
1274 OriginalPath
= gEfiShellProtocol
->GetEnv(L
"path");
1275 ASSERT((NewPath
== NULL
&& NewPathSize
== 0) || (NewPath
!= NULL
));
1276 if (OriginalPath
!= NULL
) {
1277 StrnCatGrow(&NewPath
, &NewPathSize
, OriginalPath
, 0);
1278 StrnCatGrow(&NewPath
, &NewPathSize
, L
";", 0);
1280 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1281 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\tools\\;", 0);
1282 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1283 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\efi\\boot\\;", 0);
1284 StrnCatGrow(&NewPath
, &NewPathSize
, Name
, 0);
1285 StrnCatGrow(&NewPath
, &NewPathSize
, L
"\\", 0);
1287 Status
= gEfiShellProtocol
->SetEnv(L
"path", NewPath
, TRUE
);
1288 ASSERT_EFI_ERROR(Status
);
1295 Creates the default map names for each device path in the system with
1296 a protocol depending on the Type.
1298 Creates the consistent map names for each device path in the system with
1299 a protocol depending on the Type.
1301 Note: This will reset all mappings in the system("map -r").
1303 Also sets up the default path environment variable if Type is FileSystem.
1305 @retval EFI_SUCCESS All map names were created sucessfully.
1306 @retval EFI_NOT_FOUND No protocols were found in the system.
1307 @return Error returned from gBS->LocateHandle().
1313 ShellCommandCreateInitialMappingsAndPaths(
1318 EFI_HANDLE
*HandleList
;
1320 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1321 CHAR16
*NewDefaultName
;
1322 CHAR16
*NewConsistName
;
1323 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1324 SHELL_MAP_LIST
*MapListNode
;
1325 CONST CHAR16
*CurDir
;
1326 CHAR16
*SplitCurDir
;
1328 SHELL_MAP_LIST
*MapListItem
;
1336 // Reset the static members back to zero
1341 gEfiShellProtocol
->SetEnv(L
"path", L
"", TRUE
);
1344 // First empty out the existing list.
1346 if (!IsListEmpty(&gShellMapList
.Link
)) {
1347 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1348 ; !IsListEmpty(&gShellMapList
.Link
)
1349 ; MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
1351 RemoveEntryList(&MapListNode
->Link
);
1352 SHELL_FREE_NON_NULL(MapListNode
->DevicePath
);
1353 SHELL_FREE_NON_NULL(MapListNode
->MapName
);
1354 SHELL_FREE_NON_NULL(MapListNode
->CurrentDirectoryPath
);
1355 FreePool(MapListNode
);
1360 // Find each handle with Simple File System
1362 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1363 if (HandleList
!= NULL
) {
1365 // Do a count of the handles
1367 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1370 // Get all Device Paths
1372 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1373 if (DevicePathList
== NULL
) {
1374 SHELL_FREE_NON_NULL (HandleList
);
1375 return EFI_OUT_OF_RESOURCES
;
1378 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1379 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1383 // Sort all DevicePaths
1385 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1387 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1389 // Assign new Mappings to all...
1391 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1393 // Get default name first
1395 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1396 ASSERT(NewDefaultName
!= NULL
);
1397 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, TRUE
);
1398 ASSERT_EFI_ERROR(Status
);
1399 FreePool(NewDefaultName
);
1402 // Now do consistent name
1404 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1405 if (NewConsistName
!= NULL
) {
1406 Status
= ShellCommandAddMapItemAndUpdatePath(NewConsistName
, DevicePathList
[Count
], 0, FALSE
);
1407 ASSERT_EFI_ERROR(Status
);
1408 FreePool(NewConsistName
);
1412 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1414 SHELL_FREE_NON_NULL(HandleList
);
1415 SHELL_FREE_NON_NULL(DevicePathList
);
1420 //gShellCurMapping point to node of current file system in the gShellMapList. When reset all mappings,
1421 //all nodes in the gShellMapList will be free. Then gShellCurMapping will be a dangling pointer, So,
1422 //after created new mappings, we should reset the gShellCurMapping pointer back to node of current file system.
1424 if (gShellCurMapping
!= NULL
) {
1425 gShellCurMapping
= NULL
;
1426 CurDir
= gEfiShellProtocol
->GetEnv(L
"cwd");
1427 if (CurDir
!= NULL
) {
1428 MapName
= AllocateCopyPool (StrSize(CurDir
), CurDir
);
1429 if (MapName
== NULL
) {
1430 return EFI_OUT_OF_RESOURCES
;
1432 SplitCurDir
= StrStr (MapName
, L
":");
1433 if (SplitCurDir
== NULL
) {
1434 SHELL_FREE_NON_NULL (MapName
);
1435 return EFI_UNSUPPORTED
;
1437 *(SplitCurDir
+ 1) = CHAR_NULL
;
1438 MapListItem
= ShellCommandFindMapItem (MapName
);
1439 if (MapListItem
!= NULL
) {
1440 gShellCurMapping
= MapListItem
;
1442 SHELL_FREE_NON_NULL (MapName
);
1450 // Find each handle with Block Io
1452 HandleList
= GetHandleListByProtocol(&gEfiBlockIoProtocolGuid
);
1453 if (HandleList
!= NULL
) {
1454 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1457 // Get all Device Paths
1459 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1460 if (DevicePathList
== NULL
) {
1461 SHELL_FREE_NON_NULL (HandleList
);
1462 return EFI_OUT_OF_RESOURCES
;
1465 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1466 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1470 // Sort all DevicePaths
1472 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1475 // Assign new Mappings to all...
1477 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1479 // Get default name first
1481 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeBlockIo
);
1482 ASSERT(NewDefaultName
!= NULL
);
1483 Status
= ShellCommandAddMapItemAndUpdatePath(NewDefaultName
, DevicePathList
[Count
], 0, FALSE
);
1484 ASSERT_EFI_ERROR(Status
);
1485 FreePool(NewDefaultName
);
1488 SHELL_FREE_NON_NULL(HandleList
);
1489 SHELL_FREE_NON_NULL(DevicePathList
);
1490 } else if (Count
== (UINTN
)-1) {
1491 return (EFI_NOT_FOUND
);
1494 return (EFI_SUCCESS
);
1498 Add mappings for any devices without one. Do not change any existing maps.
1500 @retval EFI_SUCCESS The operation was successful.
1504 ShellCommandUpdateMapping (
1509 EFI_HANDLE
*HandleList
;
1511 EFI_DEVICE_PATH_PROTOCOL
**DevicePathList
;
1512 CHAR16
*NewDefaultName
;
1513 CHAR16
*NewConsistName
;
1514 EFI_DEVICE_PATH_PROTOCOL
**ConsistMappingTable
;
1517 Status
= EFI_SUCCESS
;
1520 // remove mappings that represent removed devices.
1524 // Find each handle with Simple File System
1526 HandleList
= GetHandleListByProtocol(&gEfiSimpleFileSystemProtocolGuid
);
1527 if (HandleList
!= NULL
) {
1529 // Do a count of the handles
1531 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++);
1534 // Get all Device Paths
1536 DevicePathList
= AllocateZeroPool(sizeof(EFI_DEVICE_PATH_PROTOCOL
*) * Count
);
1537 if (DevicePathList
== NULL
) {
1538 return (EFI_OUT_OF_RESOURCES
);
1541 for (Count
= 0 ; HandleList
[Count
] != NULL
; Count
++) {
1542 DevicePathList
[Count
] = DevicePathFromHandle(HandleList
[Count
]);
1546 // Sort all DevicePaths
1548 PerformQuickSort(DevicePathList
, Count
, sizeof(EFI_DEVICE_PATH_PROTOCOL
*), DevicePathCompare
);
1550 ShellCommandConsistMappingInitialize(&ConsistMappingTable
);
1553 // Assign new Mappings to remainders
1555 for (Count
= 0 ; !EFI_ERROR(Status
) && HandleList
[Count
] != NULL
&& !EFI_ERROR(Status
); Count
++) {
1557 // Skip ones that already have
1559 if (gEfiShellProtocol
->GetMapFromDevicePath(&DevicePathList
[Count
]) != NULL
) {
1565 NewDefaultName
= ShellCommandCreateNewMappingName(MappingTypeFileSystem
);
1566 if (NewDefaultName
== NULL
) {
1567 Status
= EFI_OUT_OF_RESOURCES
;
1572 // Call shell protocol SetMap function now...
1574 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewDefaultName
);
1576 if (!EFI_ERROR(Status
)) {
1578 // Now do consistent name
1580 NewConsistName
= ShellCommandConsistMappingGenMappingName(DevicePathList
[Count
], ConsistMappingTable
);
1581 if (NewConsistName
!= NULL
) {
1582 Status
= gEfiShellProtocol
->SetMap(DevicePathList
[Count
], NewConsistName
);
1583 FreePool(NewConsistName
);
1587 FreePool(NewDefaultName
);
1589 ShellCommandConsistMappingUnInitialize(ConsistMappingTable
);
1590 SHELL_FREE_NON_NULL(HandleList
);
1591 SHELL_FREE_NON_NULL(DevicePathList
);
1598 // Do it all over again for gEfiBlockIoProtocolGuid
1605 Converts a SHELL_FILE_HANDLE to an EFI_FILE_PROTOCOL*.
1607 @param[in] Handle The SHELL_FILE_HANDLE to convert.
1609 @return a EFI_FILE_PROTOCOL* representing the same file.
1613 ConvertShellHandleToEfiFileProtocol(
1614 IN CONST SHELL_FILE_HANDLE Handle
1617 return ((EFI_FILE_PROTOCOL
*)(Handle
));
1621 Converts a EFI_FILE_PROTOCOL* to an SHELL_FILE_HANDLE.
1623 @param[in] Handle The pointer to EFI_FILE_PROTOCOL to convert.
1624 @param[in] Path The path to the file for verification.
1626 @return A SHELL_FILE_HANDLE representing the same file.
1627 @retval NULL There was not enough memory.
1631 ConvertEfiFileProtocolToShellHandle(
1632 IN CONST EFI_FILE_PROTOCOL
*Handle
,
1633 IN CONST CHAR16
*Path
1636 SHELL_COMMAND_FILE_HANDLE
*Buffer
;
1637 BUFFER_LIST
*NewNode
;
1640 Buffer
= AllocateZeroPool(sizeof(SHELL_COMMAND_FILE_HANDLE
));
1641 if (Buffer
== NULL
) {
1644 NewNode
= AllocateZeroPool(sizeof(BUFFER_LIST
));
1645 if (NewNode
== NULL
) {
1646 SHELL_FREE_NON_NULL(Buffer
);
1649 Buffer
->FileHandle
= (EFI_FILE_PROTOCOL
*)Handle
;
1650 Buffer
->Path
= StrnCatGrow(&Buffer
->Path
, NULL
, Path
, 0);
1651 if (Buffer
->Path
== NULL
) {
1652 SHELL_FREE_NON_NULL(NewNode
);
1653 SHELL_FREE_NON_NULL(Buffer
);
1656 NewNode
->Buffer
= Buffer
;
1658 InsertHeadList(&mFileHandleList
.Link
, &NewNode
->Link
);
1660 return ((SHELL_FILE_HANDLE
)(Handle
));
1664 Find the path that was logged with the specified SHELL_FILE_HANDLE.
1666 @param[in] Handle The SHELL_FILE_HANDLE to query on.
1668 @return A pointer to the path for the file.
1672 ShellFileHandleGetPath(
1673 IN CONST SHELL_FILE_HANDLE Handle
1678 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1679 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1680 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1682 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1683 return (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1690 Remove a SHELL_FILE_HANDLE from the list of SHELL_FILE_HANDLES.
1692 @param[in] Handle The SHELL_FILE_HANDLE to remove.
1694 @retval TRUE The item was removed.
1695 @retval FALSE The item was not found.
1699 ShellFileHandleRemove(
1700 IN CONST SHELL_FILE_HANDLE Handle
1705 for (Node
= (BUFFER_LIST
*)GetFirstNode(&mFileHandleList
.Link
)
1706 ; !IsNull(&mFileHandleList
.Link
, &Node
->Link
)
1707 ; Node
= (BUFFER_LIST
*)GetNextNode(&mFileHandleList
.Link
, &Node
->Link
)
1709 if ((Node
->Buffer
) && (((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->FileHandle
== Handle
)){
1710 RemoveEntryList(&Node
->Link
);
1711 SHELL_FREE_NON_NULL(((SHELL_COMMAND_FILE_HANDLE
*)Node
->Buffer
)->Path
);
1712 SHELL_FREE_NON_NULL(Node
->Buffer
);
1713 SHELL_FREE_NON_NULL(Node
);
1721 Function to determine if a SHELL_FILE_HANDLE is at the end of the file.
1723 This will NOT work on directories.
1725 If Handle is NULL, then ASSERT.
1727 @param[in] Handle the file handle
1729 @retval TRUE the position is at the end of the file
1730 @retval FALSE the position is not at the end of the file
1735 IN SHELL_FILE_HANDLE Handle
1738 EFI_FILE_INFO
*Info
;
1743 // ASSERT if Handle is NULL
1745 ASSERT(Handle
!= NULL
);
1747 gEfiShellProtocol
->GetFilePosition(Handle
, &Pos
);
1748 Info
= gEfiShellProtocol
->GetFileInfo (Handle
);
1749 gEfiShellProtocol
->SetFilePosition(Handle
, Pos
);
1755 if (Pos
== Info
->FileSize
) {
1767 Frees any BUFFER_LIST defined type.
1769 @param[in] List The BUFFER_LIST object to free.
1774 IN BUFFER_LIST
*List
1777 BUFFER_LIST
*BufferListEntry
;
1783 // enumerate through the buffer list and free all memory
1785 for ( BufferListEntry
= ( BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1786 ; !IsListEmpty (&List
->Link
)
1787 ; BufferListEntry
= (BUFFER_LIST
*)GetFirstNode(&List
->Link
)
1789 RemoveEntryList(&BufferListEntry
->Link
);
1790 if (BufferListEntry
->Buffer
!= NULL
) {
1791 FreePool(BufferListEntry
->Buffer
);
1793 FreePool(BufferListEntry
);
1798 Dump some hexadecimal data to the screen.
1800 @param[in] Indent How many spaces to indent the output.
1801 @param[in] Offset The offset of the printing.
1802 @param[in] DataSize The size in bytes of UserData.
1803 @param[in] UserData The data to print out.
1825 while (DataSize
!= 0) {
1827 if (Size
> DataSize
) {
1831 for (Index
= 0; Index
< Size
; Index
+= 1) {
1832 TempByte
= Data
[Index
];
1833 Val
[Index
* 3 + 0] = Hex
[TempByte
>> 4];
1834 Val
[Index
* 3 + 1] = Hex
[TempByte
& 0xF];
1835 Val
[Index
* 3 + 2] = (CHAR8
) ((Index
== 7) ? '-' : ' ');
1836 Str
[Index
] = (CHAR8
) ((TempByte
< ' ' || TempByte
> '~') ? '.' : TempByte
);
1841 ShellPrintEx(-1, -1, L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
1850 Dump HEX data into buffer.
1852 @param[in] Buffer HEX data to be dumped in Buffer.
1853 @param[in] Indent How many spaces to indent the output.
1854 @param[in] Offset The offset of the printing.
1855 @param[in] DataSize The size in bytes of UserData.
1856 @param[in] UserData The data to print out.
1879 while (DataSize
!= 0) {
1881 if (Size
> DataSize
) {
1885 for (Index
= 0; Index
< Size
; Index
+= 1) {
1886 TempByte
= Data
[Index
];
1887 Val
[Index
* 3 + 0] = Hex
[TempByte
>> 4];
1888 Val
[Index
* 3 + 1] = Hex
[TempByte
& 0xF];
1889 Val
[Index
* 3 + 2] = (CHAR8
) ((Index
== 7) ? '-' : ' ');
1890 Str
[Index
] = (CHAR8
) ((TempByte
< ' ' || TempByte
> 'z') ? '.' : TempByte
);
1895 TempRetVal
= CatSPrint (RetVal
, L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
1896 SHELL_FREE_NON_NULL (RetVal
);
1897 RetVal
= TempRetVal
;