2 Provides interface to shell functionality for shell commands and applications.
4 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
5 Copyright 2016-2018 Dell Technologies.<BR>
6 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include "UefiShellLib.h"
18 #include <Library/SortLib.h>
19 #include <Library/BaseLib.h>
24 SHELL_PARAM_ITEM EmptyParamList
[] = {
27 SHELL_PARAM_ITEM SfoParamList
[] = {
31 EFI_SHELL_ENVIRONMENT2
*mEfiShellEnvironment2
;
32 EFI_SHELL_INTERFACE
*mEfiShellInterface
;
33 EFI_SHELL_PROTOCOL
*gEfiShellProtocol
;
34 EFI_SHELL_PARAMETERS_PROTOCOL
*gEfiShellParametersProtocol
;
35 EFI_HANDLE mEfiShellEnvironment2Handle
;
36 FILE_HANDLE_FUNCTION_MAP FileFunctionMap
;
37 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollationProtocol
;
40 Return a clean, fully-qualified version of an input path. If the return value
41 is non-NULL the caller must free the memory when it is no longer needed.
43 If asserts are disabled, and if the input parameter is NULL, NULL is returned.
45 If there is not enough memory available to create the fully-qualified path or
46 a copy of the input path, NULL is returned.
48 If there is no working directory, a clean copy of Path is returned.
50 Otherwise, the current file system or working directory (as appropriate) is
51 prepended to Path and the resulting path is cleaned and returned.
53 NOTE: If the input path is an empty string, then the current working directory
54 (if it exists) is returned. In other words, an empty input path is treated
55 exactly the same as ".".
57 @param[in] Path A pointer to some file or directory path.
59 @retval NULL The input path is NULL or out of memory.
61 @retval non-NULL A pointer to a clean, fully-qualified version of Path.
62 If there is no working directory, then a pointer to a
63 clean, but not necessarily fully-qualified version of
64 Path. The caller must free this memory when it is no
73 CONST CHAR16
*WorkingPath
;
74 CONST CHAR16
*InputPath
;
76 CHAR16
*InputFileSystem
;
77 UINTN FileSystemCharCount
;
78 CHAR16
*FullyQualifiedPath
;
81 FullyQualifiedPath
= NULL
;
85 // Handle erroneous input when asserts are disabled.
91 // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext,
92 // we have to consider the file system part separately from the "path" part.
93 // If there is a file system in the path, we have to get the current working
94 // directory for that file system. Then we need to use the part of the path
95 // following the ":". If a path does not contain ":", we use it as given.
97 InputPath
= StrStr(Path
, L
":");
98 if (InputPath
!= NULL
) {
100 FileSystemCharCount
= ((UINTN
)InputPath
- (UINTN
)Path
+ sizeof(CHAR16
)) / sizeof(CHAR16
);
101 InputFileSystem
= AllocateCopyPool(FileSystemCharCount
* sizeof(CHAR16
), Path
);
102 if (InputFileSystem
!= NULL
) {
103 InputFileSystem
[FileSystemCharCount
- 1] = CHAR_NULL
;
105 WorkingPath
= ShellGetCurrentDir(InputFileSystem
);
106 SHELL_FREE_NON_NULL(InputFileSystem
);
109 WorkingPath
= ShellGetEnvironmentVariable(L
"cwd");
112 if (WorkingPath
== NULL
) {
114 // With no working directory, all we can do is copy and clean the input path.
116 FullyQualifiedPath
= AllocateCopyPool(StrSize(Path
), Path
);
119 // Allocate space for both strings plus one more character.
121 Size
= StrSize(WorkingPath
) + StrSize(InputPath
);
122 FullyQualifiedPath
= AllocateZeroPool(Size
);
123 if (FullyQualifiedPath
== NULL
) {
125 // Try to copy and clean just the input. No harm if not enough memory.
127 FullyQualifiedPath
= AllocateCopyPool(StrSize(Path
), Path
);
129 if (*InputPath
== L
'\\' || *InputPath
== L
'/') {
131 // Absolute path: start with the current working directory, then
132 // truncate the new path after the file system part.
134 StrCpyS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), WorkingPath
);
135 CharPtr
= StrStr(FullyQualifiedPath
, L
":");
136 if (CharPtr
!= NULL
) {
137 *(CharPtr
+ 1) = CHAR_NULL
;
141 // Relative path: start with the working directory and append "\".
143 StrCpyS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), WorkingPath
);
144 StrCatS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), L
"\\");
147 // Now append the absolute or relative path.
149 StrCatS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), InputPath
);
153 PathCleanUpDirectories(FullyQualifiedPath
);
155 return FullyQualifiedPath
;
159 Check if a Unicode character is a hexadecimal character.
161 This internal function checks if a Unicode character is a
162 numeric character. The valid hexadecimal characters are
163 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
165 @param Char The character to check against.
167 @retval TRUE If the Char is a hexadecmial character.
168 @retval FALSE If the Char is not a hexadecmial character.
173 ShellIsHexaDecimalDigitCharacter (
177 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
181 Check if a Unicode character is a decimal character.
183 This internal function checks if a Unicode character is a
184 decimal character. The valid characters are
188 @param Char The character to check against.
190 @retval TRUE If the Char is a hexadecmial character.
191 @retval FALSE If the Char is not a hexadecmial character.
196 ShellIsDecimalDigitCharacter (
200 return (BOOLEAN
) (Char
>= L
'0' && Char
<= L
'9');
204 Helper function to find ShellEnvironment2 for constructor.
206 @param[in] ImageHandle A copy of the calling image's handle.
208 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
212 IN EFI_HANDLE ImageHandle
222 Status
= gBS
->OpenProtocol(ImageHandle
,
223 &gEfiShellEnvironment2Guid
,
224 (VOID
**)&mEfiShellEnvironment2
,
227 EFI_OPEN_PROTOCOL_GET_PROTOCOL
230 // look for the mEfiShellEnvironment2 protocol at a higher level
232 if (EFI_ERROR (Status
) || !(CompareGuid (&mEfiShellEnvironment2
->SESGuid
, &gEfiShellEnvironment2ExtGuid
))){
234 // figure out how big of a buffer we need.
236 Status
= gBS
->LocateHandle (ByProtocol
,
237 &gEfiShellEnvironment2Guid
,
238 NULL
, // ignored for ByProtocol
243 // maybe it's not there???
245 if (Status
== EFI_BUFFER_TOO_SMALL
) {
246 Buffer
= (EFI_HANDLE
*)AllocateZeroPool(BufferSize
);
247 if (Buffer
== NULL
) {
248 return (EFI_OUT_OF_RESOURCES
);
250 Status
= gBS
->LocateHandle (ByProtocol
,
251 &gEfiShellEnvironment2Guid
,
252 NULL
, // ignored for ByProtocol
257 if (!EFI_ERROR (Status
) && Buffer
!= NULL
) {
259 // now parse the list of returned handles
261 Status
= EFI_NOT_FOUND
;
262 for (HandleIndex
= 0; HandleIndex
< (BufferSize
/sizeof(Buffer
[0])); HandleIndex
++) {
263 Status
= gBS
->OpenProtocol(Buffer
[HandleIndex
],
264 &gEfiShellEnvironment2Guid
,
265 (VOID
**)&mEfiShellEnvironment2
,
268 EFI_OPEN_PROTOCOL_GET_PROTOCOL
270 if (CompareGuid (&mEfiShellEnvironment2
->SESGuid
, &gEfiShellEnvironment2ExtGuid
)) {
271 mEfiShellEnvironment2Handle
= Buffer
[HandleIndex
];
272 Status
= EFI_SUCCESS
;
278 if (Buffer
!= NULL
) {
285 Function to do most of the work of the constructor. Allows for calling
286 multiple times without complete re-initialization.
288 @param[in] ImageHandle A copy of the ImageHandle.
289 @param[in] SystemTable A pointer to the SystemTable for the application.
291 @retval EFI_SUCCESS The operationw as successful.
294 ShellLibConstructorWorker (
295 IN EFI_HANDLE ImageHandle
,
296 IN EFI_SYSTEM_TABLE
*SystemTable
301 if (gEfiShellProtocol
== NULL
) {
303 // UEFI 2.0 shell interfaces (used preferentially)
305 Status
= gBS
->OpenProtocol (
307 &gEfiShellProtocolGuid
,
308 (VOID
**)&gEfiShellProtocol
,
311 EFI_OPEN_PROTOCOL_GET_PROTOCOL
313 if (EFI_ERROR (Status
)) {
315 // Search for the shell protocol
317 Status
= gBS
->LocateProtocol (
318 &gEfiShellProtocolGuid
,
320 (VOID
**)&gEfiShellProtocol
322 if (EFI_ERROR (Status
)) {
323 gEfiShellProtocol
= NULL
;
328 if (gEfiShellParametersProtocol
== NULL
) {
329 Status
= gBS
->OpenProtocol (
331 &gEfiShellParametersProtocolGuid
,
332 (VOID
**)&gEfiShellParametersProtocol
,
335 EFI_OPEN_PROTOCOL_GET_PROTOCOL
337 if (EFI_ERROR (Status
)) {
338 gEfiShellParametersProtocol
= NULL
;
342 if (gEfiShellProtocol
== NULL
) {
344 // Moved to seperate function due to complexity
346 Status
= ShellFindSE2(ImageHandle
);
348 if (EFI_ERROR(Status
)) {
349 DEBUG((DEBUG_ERROR
, "Status: 0x%08x\r\n", Status
));
350 mEfiShellEnvironment2
= NULL
;
352 Status
= gBS
->OpenProtocol(ImageHandle
,
353 &gEfiShellInterfaceGuid
,
354 (VOID
**)&mEfiShellInterface
,
357 EFI_OPEN_PROTOCOL_GET_PROTOCOL
359 if (EFI_ERROR(Status
)) {
360 mEfiShellInterface
= NULL
;
365 // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol
366 // or UEFI Shell's Shell protocol.
367 // When ShellLib is linked to a driver producing DynamicCommand protocol,
368 // ShellParameters protocol is set by DynamicCommand.Handler().
370 if ((mEfiShellEnvironment2
!= NULL
&& mEfiShellInterface
!= NULL
) ||
371 (gEfiShellProtocol
!= NULL
)
373 if (gEfiShellProtocol
!= NULL
) {
374 FileFunctionMap
.GetFileInfo
= gEfiShellProtocol
->GetFileInfo
;
375 FileFunctionMap
.SetFileInfo
= gEfiShellProtocol
->SetFileInfo
;
376 FileFunctionMap
.ReadFile
= gEfiShellProtocol
->ReadFile
;
377 FileFunctionMap
.WriteFile
= gEfiShellProtocol
->WriteFile
;
378 FileFunctionMap
.CloseFile
= gEfiShellProtocol
->CloseFile
;
379 FileFunctionMap
.DeleteFile
= gEfiShellProtocol
->DeleteFile
;
380 FileFunctionMap
.GetFilePosition
= gEfiShellProtocol
->GetFilePosition
;
381 FileFunctionMap
.SetFilePosition
= gEfiShellProtocol
->SetFilePosition
;
382 FileFunctionMap
.FlushFile
= gEfiShellProtocol
->FlushFile
;
383 FileFunctionMap
.GetFileSize
= gEfiShellProtocol
->GetFileSize
;
385 FileFunctionMap
.GetFileInfo
= (EFI_SHELL_GET_FILE_INFO
)FileHandleGetInfo
;
386 FileFunctionMap
.SetFileInfo
= (EFI_SHELL_SET_FILE_INFO
)FileHandleSetInfo
;
387 FileFunctionMap
.ReadFile
= (EFI_SHELL_READ_FILE
)FileHandleRead
;
388 FileFunctionMap
.WriteFile
= (EFI_SHELL_WRITE_FILE
)FileHandleWrite
;
389 FileFunctionMap
.CloseFile
= (EFI_SHELL_CLOSE_FILE
)FileHandleClose
;
390 FileFunctionMap
.DeleteFile
= (EFI_SHELL_DELETE_FILE
)FileHandleDelete
;
391 FileFunctionMap
.GetFilePosition
= (EFI_SHELL_GET_FILE_POSITION
)FileHandleGetPosition
;
392 FileFunctionMap
.SetFilePosition
= (EFI_SHELL_SET_FILE_POSITION
)FileHandleSetPosition
;
393 FileFunctionMap
.FlushFile
= (EFI_SHELL_FLUSH_FILE
)FileHandleFlush
;
394 FileFunctionMap
.GetFileSize
= (EFI_SHELL_GET_FILE_SIZE
)FileHandleGetSize
;
396 return (EFI_SUCCESS
);
398 return (EFI_NOT_FOUND
);
401 Constructor for the Shell library.
403 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
405 @param ImageHandle the image handle of the process
406 @param SystemTable the EFI System Table pointer
408 @retval EFI_SUCCESS the initialization was complete sucessfully
409 @return others an error ocurred during initialization
413 ShellLibConstructor (
414 IN EFI_HANDLE ImageHandle
,
415 IN EFI_SYSTEM_TABLE
*SystemTable
418 mEfiShellEnvironment2
= NULL
;
419 gEfiShellProtocol
= NULL
;
420 gEfiShellParametersProtocol
= NULL
;
421 mEfiShellInterface
= NULL
;
422 mEfiShellEnvironment2Handle
= NULL
;
423 mUnicodeCollationProtocol
= NULL
;
426 // verify that auto initialize is not set false
428 if (PcdGetBool(PcdShellLibAutoInitialize
) == 0) {
429 return (EFI_SUCCESS
);
432 return (ShellLibConstructorWorker(ImageHandle
, SystemTable
));
436 Destructor for the library. free any resources.
438 @param[in] ImageHandle A copy of the ImageHandle.
439 @param[in] SystemTable A pointer to the SystemTable for the application.
441 @retval EFI_SUCCESS The operation was successful.
442 @return An error from the CloseProtocol function.
447 IN EFI_HANDLE ImageHandle
,
448 IN EFI_SYSTEM_TABLE
*SystemTable
453 if (mEfiShellEnvironment2
!= NULL
) {
454 Status
= gBS
->CloseProtocol(mEfiShellEnvironment2Handle
==NULL
?ImageHandle
:mEfiShellEnvironment2Handle
,
455 &gEfiShellEnvironment2Guid
,
458 if (!EFI_ERROR (Status
)) {
459 mEfiShellEnvironment2
= NULL
;
460 mEfiShellEnvironment2Handle
= NULL
;
463 if (mEfiShellInterface
!= NULL
) {
464 Status
= gBS
->CloseProtocol(ImageHandle
,
465 &gEfiShellInterfaceGuid
,
468 if (!EFI_ERROR (Status
)) {
469 mEfiShellInterface
= NULL
;
472 if (gEfiShellProtocol
!= NULL
) {
473 Status
= gBS
->CloseProtocol(ImageHandle
,
474 &gEfiShellProtocolGuid
,
477 if (!EFI_ERROR (Status
)) {
478 gEfiShellProtocol
= NULL
;
481 if (gEfiShellParametersProtocol
!= NULL
) {
482 Status
= gBS
->CloseProtocol(ImageHandle
,
483 &gEfiShellParametersProtocolGuid
,
486 if (!EFI_ERROR (Status
)) {
487 gEfiShellParametersProtocol
= NULL
;
491 return (EFI_SUCCESS
);
495 This function causes the shell library to initialize itself. If the shell library
496 is already initialized it will de-initialize all the current protocol poitners and
497 re-populate them again.
499 When the library is used with PcdShellLibAutoInitialize set to true this function
500 will return EFI_SUCCESS and perform no actions.
502 This function is intended for internal access for shell commands only.
504 @retval EFI_SUCCESS the initialization was complete sucessfully
516 // if auto initialize is not false then skip
518 if (PcdGetBool(PcdShellLibAutoInitialize
) != 0) {
519 return (EFI_SUCCESS
);
523 // deinit the current stuff
525 Status
= ShellLibDestructor (gImageHandle
, gST
);
526 ASSERT_EFI_ERROR (Status
);
529 // init the new stuff
531 return (ShellLibConstructorWorker(gImageHandle
, gST
));
535 This function will retrieve the information about the file for the handle
536 specified and store it in allocated pool memory.
538 This function allocates a buffer to store the file's information. It is the
539 caller's responsibility to free the buffer
541 @param FileHandle The file handle of the file for which information is
544 @retval NULL information could not be retrieved.
546 @return the information about the file
551 IN SHELL_FILE_HANDLE FileHandle
554 return (FileFunctionMap
.GetFileInfo(FileHandle
));
558 This function sets the information about the file for the opened handle
561 @param[in] FileHandle The file handle of the file for which information
564 @param[in] FileInfo The information to set.
566 @retval EFI_SUCCESS The information was set.
567 @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
568 @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
569 @retval EFI_NO_MEDIA The device has no medium.
570 @retval EFI_DEVICE_ERROR The device reported an error.
571 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
572 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
573 @retval EFI_ACCESS_DENIED The file was opened read only.
574 @retval EFI_VOLUME_FULL The volume is full.
579 IN SHELL_FILE_HANDLE FileHandle
,
580 IN EFI_FILE_INFO
*FileInfo
583 return (FileFunctionMap
.SetFileInfo(FileHandle
, FileInfo
));
587 This function will open a file or directory referenced by DevicePath.
589 This function opens a file with the open mode according to the file path. The
590 Attributes is valid only for EFI_FILE_MODE_CREATE.
592 @param FilePath on input the device path to the file. On output
593 the remaining device path.
594 @param FileHandle pointer to the file handle.
595 @param OpenMode the mode to open the file with.
596 @param Attributes the file's file attributes.
598 @retval EFI_SUCCESS The information was set.
599 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
600 @retval EFI_UNSUPPORTED Could not open the file path.
601 @retval EFI_NOT_FOUND The specified file could not be found on the
602 device or the file system could not be found on
604 @retval EFI_NO_MEDIA The device has no medium.
605 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
606 medium is no longer supported.
607 @retval EFI_DEVICE_ERROR The device reported an error.
608 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
609 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
610 @retval EFI_ACCESS_DENIED The file was opened read only.
611 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
613 @retval EFI_VOLUME_FULL The volume is full.
617 ShellOpenFileByDevicePath(
618 IN OUT EFI_DEVICE_PATH_PROTOCOL
**FilePath
,
619 OUT SHELL_FILE_HANDLE
*FileHandle
,
626 EFI_FILE_PROTOCOL
*File
;
628 if (FilePath
== NULL
|| FileHandle
== NULL
) {
629 return (EFI_INVALID_PARAMETER
);
633 // which shell interface should we use
635 if (gEfiShellProtocol
!= NULL
) {
637 // use UEFI Shell 2.0 method.
639 FileName
= gEfiShellProtocol
->GetFilePathFromDevicePath(*FilePath
);
640 if (FileName
== NULL
) {
641 return (EFI_INVALID_PARAMETER
);
643 Status
= ShellOpenFileByName(FileName
, FileHandle
, OpenMode
, Attributes
);
650 // use old shell method.
652 Status
= EfiOpenFileByDevicePath (FilePath
, &File
, OpenMode
, Attributes
);
653 if (EFI_ERROR (Status
)) {
658 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
660 *FileHandle
= (VOID
*)File
;
661 return (EFI_SUCCESS
);
665 This function will open a file or directory referenced by filename.
667 If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
668 otherwise, the Filehandle is NULL. The Attributes is valid only for
669 EFI_FILE_MODE_CREATE.
671 if FileName is NULL then ASSERT()
673 @param FileName pointer to file name
674 @param FileHandle pointer to the file handle.
675 @param OpenMode the mode to open the file with.
676 @param Attributes the file's file attributes.
678 @retval EFI_SUCCESS The information was set.
679 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
680 @retval EFI_UNSUPPORTED Could not open the file path.
681 @retval EFI_NOT_FOUND The specified file could not be found on the
682 device or the file system could not be found
684 @retval EFI_NO_MEDIA The device has no medium.
685 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
686 medium is no longer supported.
687 @retval EFI_DEVICE_ERROR The device reported an error.
688 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
689 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
690 @retval EFI_ACCESS_DENIED The file was opened read only.
691 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
693 @retval EFI_VOLUME_FULL The volume is full.
698 IN CONST CHAR16
*FileName
,
699 OUT SHELL_FILE_HANDLE
*FileHandle
,
704 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
706 EFI_FILE_INFO
*FileInfo
;
707 CHAR16
*FileNameCopy
;
711 // ASSERT if FileName is NULL
713 ASSERT(FileName
!= NULL
);
715 if (FileName
== NULL
) {
716 return (EFI_INVALID_PARAMETER
);
719 if (gEfiShellProtocol
!= NULL
) {
720 if ((OpenMode
& EFI_FILE_MODE_CREATE
) == EFI_FILE_MODE_CREATE
) {
723 // Create only a directory
725 if ((Attributes
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
) {
726 return ShellCreateDirectory(FileName
, FileHandle
);
730 // Create the directory to create the file in
732 FileNameCopy
= AllocateCopyPool (StrSize (FileName
), FileName
);
733 if (FileNameCopy
== NULL
) {
734 return (EFI_OUT_OF_RESOURCES
);
736 PathCleanUpDirectories (FileNameCopy
);
737 if (PathRemoveLastItem (FileNameCopy
)) {
738 if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy
, FileHandle
))) {
739 ShellCloseFile (FileHandle
);
742 SHELL_FREE_NON_NULL (FileNameCopy
);
746 // Use UEFI Shell 2.0 method to create the file
748 Status
= gEfiShellProtocol
->OpenFileByName(FileName
,
751 if (EFI_ERROR(Status
)) {
755 if (mUnicodeCollationProtocol
== NULL
) {
756 Status
= gBS
->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid
, NULL
, (VOID
**)&mUnicodeCollationProtocol
);
757 if (EFI_ERROR (Status
)) {
758 gEfiShellProtocol
->CloseFile (*FileHandle
);
763 if ((mUnicodeCollationProtocol
->StriColl (mUnicodeCollationProtocol
, (CHAR16
*)FileName
, L
"NUL") != 0) &&
764 (mUnicodeCollationProtocol
->StriColl (mUnicodeCollationProtocol
, (CHAR16
*)FileName
, L
"NULL") != 0) &&
765 !EFI_ERROR(Status
) && ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0)){
766 FileInfo
= FileFunctionMap
.GetFileInfo(*FileHandle
);
767 ASSERT(FileInfo
!= NULL
);
768 FileInfo
->Attribute
= Attributes
;
769 Status2
= FileFunctionMap
.SetFileInfo(*FileHandle
, FileInfo
);
771 if (EFI_ERROR (Status2
)) {
772 gEfiShellProtocol
->CloseFile(*FileHandle
);
779 // Using EFI Shell version
780 // this means convert name to path and call that function
781 // since this will use EFI method again that will open it.
783 ASSERT(mEfiShellEnvironment2
!= NULL
);
784 FilePath
= mEfiShellEnvironment2
->NameToPath ((CHAR16
*)FileName
);
785 if (FilePath
!= NULL
) {
786 return (ShellOpenFileByDevicePath(&FilePath
,
791 return (EFI_DEVICE_ERROR
);
794 This function create a directory
796 If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
797 otherwise, the Filehandle is NULL. If the directory already existed, this
798 function opens the existing directory.
800 @param DirectoryName pointer to directory name
801 @param FileHandle pointer to the file handle.
803 @retval EFI_SUCCESS The information was set.
804 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
805 @retval EFI_UNSUPPORTED Could not open the file path.
806 @retval EFI_NOT_FOUND The specified file could not be found on the
807 device or the file system could not be found
809 @retval EFI_NO_MEDIA The device has no medium.
810 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
811 medium is no longer supported.
812 @retval EFI_DEVICE_ERROR The device reported an error.
813 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
814 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
815 @retval EFI_ACCESS_DENIED The file was opened read only.
816 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
818 @retval EFI_VOLUME_FULL The volume is full.
819 @sa ShellOpenFileByName
823 ShellCreateDirectory(
824 IN CONST CHAR16
*DirectoryName
,
825 OUT SHELL_FILE_HANDLE
*FileHandle
828 if (gEfiShellProtocol
!= NULL
) {
830 // Use UEFI Shell 2.0 method
832 return (gEfiShellProtocol
->CreateFile(DirectoryName
,
837 return (ShellOpenFileByName(DirectoryName
,
839 EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
,
846 This function reads information from an opened file.
848 If FileHandle is not a directory, the function reads the requested number of
849 bytes from the file at the file's current position and returns them in Buffer.
850 If the read goes beyond the end of the file, the read length is truncated to the
851 end of the file. The file's current position is increased by the number of bytes
852 returned. If FileHandle is a directory, the function reads the directory entry
853 at the file's current position and returns the entry in Buffer. If the Buffer
854 is not large enough to hold the current directory entry, then
855 EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
856 BufferSize is set to be the size of the buffer needed to read the entry. On
857 success, the current position is updated to the next directory entry. If there
858 are no more directory entries, the read returns a zero-length buffer.
859 EFI_FILE_INFO is the structure returned as the directory entry.
861 @param FileHandle the opened file handle
862 @param BufferSize on input the size of buffer in bytes. on return
863 the number of bytes written.
864 @param Buffer the buffer to put read data into.
866 @retval EFI_SUCCESS Data was read.
867 @retval EFI_NO_MEDIA The device has no media.
868 @retval EFI_DEVICE_ERROR The device reported an error.
869 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
870 @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
877 IN SHELL_FILE_HANDLE FileHandle
,
878 IN OUT UINTN
*BufferSize
,
882 return (FileFunctionMap
.ReadFile(FileHandle
, BufferSize
, Buffer
));
887 Write data to a file.
889 This function writes the specified number of bytes to the file at the current
890 file position. The current file position is advanced the actual number of bytes
891 written, which is returned in BufferSize. Partial writes only occur when there
892 has been a data error during the write attempt (such as "volume space full").
893 The file is automatically grown to hold the data if required. Direct writes to
894 opened directories are not supported.
896 @param FileHandle The opened file for writing
897 @param BufferSize on input the number of bytes in Buffer. On output
898 the number of bytes written.
899 @param Buffer the buffer containing data to write is stored.
901 @retval EFI_SUCCESS Data was written.
902 @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
903 @retval EFI_NO_MEDIA The device has no media.
904 @retval EFI_DEVICE_ERROR The device reported an error.
905 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
906 @retval EFI_WRITE_PROTECTED The device is write-protected.
907 @retval EFI_ACCESS_DENIED The file was open for read only.
908 @retval EFI_VOLUME_FULL The volume is full.
913 IN SHELL_FILE_HANDLE FileHandle
,
914 IN OUT UINTN
*BufferSize
,
918 return (FileFunctionMap
.WriteFile(FileHandle
, BufferSize
, Buffer
));
922 Close an open file handle.
924 This function closes a specified file handle. All "dirty" cached file data is
925 flushed to the device, and the file is closed. In all cases the handle is
928 @param FileHandle the file handle to close.
930 @retval EFI_SUCCESS the file handle was closed sucessfully.
935 IN SHELL_FILE_HANDLE
*FileHandle
938 return (FileFunctionMap
.CloseFile(*FileHandle
));
942 Delete a file and close the handle
944 This function closes and deletes a file. In all cases the file handle is closed.
945 If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
946 returned, but the handle is still closed.
948 @param FileHandle the file handle to delete
950 @retval EFI_SUCCESS the file was closed sucessfully
951 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
953 @retval INVALID_PARAMETER One of the parameters has an invalid value.
958 IN SHELL_FILE_HANDLE
*FileHandle
961 return (FileFunctionMap
.DeleteFile(*FileHandle
));
965 Set the current position in a file.
967 This function sets the current file position for the handle to the position
968 supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
969 absolute positioning is supported, and seeking past the end of the file is
970 allowed (a subsequent write would grow the file). Seeking to position
971 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
972 If FileHandle is a directory, the only position that may be set is zero. This
973 has the effect of starting the read process of the directory entries over.
975 @param FileHandle The file handle on which the position is being set
976 @param Position Byte position from begining of file
978 @retval EFI_SUCCESS Operation completed sucessfully.
979 @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
981 @retval INVALID_PARAMETER One of the parameters has an invalid value.
985 ShellSetFilePosition (
986 IN SHELL_FILE_HANDLE FileHandle
,
990 return (FileFunctionMap
.SetFilePosition(FileHandle
, Position
));
994 Gets a file's current position
996 This function retrieves the current file position for the file handle. For
997 directories, the current file position has no meaning outside of the file
998 system driver and as such the operation is not supported. An error is returned
999 if FileHandle is a directory.
1001 @param FileHandle The open file handle on which to get the position.
1002 @param Position Byte position from begining of file.
1004 @retval EFI_SUCCESS the operation completed sucessfully.
1005 @retval INVALID_PARAMETER One of the parameters has an invalid value.
1006 @retval EFI_UNSUPPORTED the request is not valid on directories.
1010 ShellGetFilePosition (
1011 IN SHELL_FILE_HANDLE FileHandle
,
1012 OUT UINT64
*Position
1015 return (FileFunctionMap
.GetFilePosition(FileHandle
, Position
));
1018 Flushes data on a file
1020 This function flushes all modified data associated with a file to a device.
1022 @param FileHandle The file handle on which to flush data
1024 @retval EFI_SUCCESS The data was flushed.
1025 @retval EFI_NO_MEDIA The device has no media.
1026 @retval EFI_DEVICE_ERROR The device reported an error.
1027 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1028 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
1029 @retval EFI_ACCESS_DENIED The file was opened for read only.
1034 IN SHELL_FILE_HANDLE FileHandle
1037 return (FileFunctionMap
.FlushFile(FileHandle
));
1040 /** Retrieve first entry from a directory.
1042 This function takes an open directory handle and gets information from the
1043 first entry in the directory. A buffer is allocated to contain
1044 the information and a pointer to the buffer is returned in *Buffer. The
1045 caller can use ShellFindNextFile() to get subsequent directory entries.
1047 The buffer will be freed by ShellFindNextFile() when the last directory
1048 entry is read. Otherwise, the caller must free the buffer, using FreePool,
1049 when finished with it.
1051 @param[in] DirHandle The file handle of the directory to search.
1052 @param[out] Buffer The pointer to the buffer for the file's information.
1054 @retval EFI_SUCCESS Found the first file.
1055 @retval EFI_NOT_FOUND Cannot find the directory.
1056 @retval EFI_NO_MEDIA The device has no media.
1057 @retval EFI_DEVICE_ERROR The device reported an error.
1058 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1059 @return Others status of ShellGetFileInfo, ShellSetFilePosition,
1064 ShellFindFirstFile (
1065 IN SHELL_FILE_HANDLE DirHandle
,
1066 OUT EFI_FILE_INFO
**Buffer
1070 // pass to file handle lib
1072 return (FileHandleFindFirstFile(DirHandle
, Buffer
));
1074 /** Retrieve next entries from a directory.
1076 To use this function, the caller must first call the ShellFindFirstFile()
1077 function to get the first directory entry. Subsequent directory entries are
1078 retrieved by using the ShellFindNextFile() function. This function can
1079 be called several times to get each entry from the directory. If the call of
1080 ShellFindNextFile() retrieved the last directory entry, the next call of
1081 this function will set *NoFile to TRUE and free the buffer.
1083 @param[in] DirHandle The file handle of the directory.
1084 @param[out] Buffer The pointer to buffer for file's information.
1085 @param[out] NoFile The pointer to boolean when last file is found.
1087 @retval EFI_SUCCESS Found the next file, or reached last file
1088 @retval EFI_NO_MEDIA The device has no media.
1089 @retval EFI_DEVICE_ERROR The device reported an error.
1090 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1095 IN SHELL_FILE_HANDLE DirHandle
,
1096 OUT EFI_FILE_INFO
*Buffer
,
1101 // pass to file handle lib
1103 return (FileHandleFindNextFile(DirHandle
, Buffer
, NoFile
));
1106 Retrieve the size of a file.
1108 if FileHandle is NULL then ASSERT()
1109 if Size is NULL then ASSERT()
1111 This function extracts the file size info from the FileHandle's EFI_FILE_INFO
1114 @param FileHandle file handle from which size is retrieved
1115 @param Size pointer to size
1117 @retval EFI_SUCCESS operation was completed sucessfully
1118 @retval EFI_DEVICE_ERROR cannot access the file
1123 IN SHELL_FILE_HANDLE FileHandle
,
1127 return (FileFunctionMap
.GetFileSize(FileHandle
, Size
));
1130 Retrieves the status of the break execution flag
1132 this function is useful to check whether the application is being asked to halt by the shell.
1134 @retval TRUE the execution break is enabled
1135 @retval FALSE the execution break is not enabled
1139 ShellGetExecutionBreakFlag(
1144 // Check for UEFI Shell 2.0 protocols
1146 if (gEfiShellProtocol
!= NULL
) {
1149 // We are using UEFI Shell 2.0; see if the event has been triggered
1151 if (gBS
->CheckEvent(gEfiShellProtocol
->ExecutionBreak
) != EFI_SUCCESS
) {
1158 // using EFI Shell; call the function to check
1160 if (mEfiShellEnvironment2
!= NULL
) {
1161 return (mEfiShellEnvironment2
->GetExecutionBreak());
1167 return the value of an environment variable
1169 this function gets the value of the environment variable set by the
1170 ShellSetEnvironmentVariable function
1172 @param EnvKey The key name of the environment variable.
1174 @retval NULL the named environment variable does not exist.
1175 @return != NULL pointer to the value of the environment variable
1179 ShellGetEnvironmentVariable (
1180 IN CONST CHAR16
*EnvKey
1184 // Check for UEFI Shell 2.0 protocols
1186 if (gEfiShellProtocol
!= NULL
) {
1187 return (gEfiShellProtocol
->GetEnv(EnvKey
));
1191 // Check for EFI shell
1193 if (mEfiShellEnvironment2
!= NULL
) {
1194 return (mEfiShellEnvironment2
->GetEnv((CHAR16
*)EnvKey
));
1200 set the value of an environment variable
1202 This function changes the current value of the specified environment variable. If the
1203 environment variable exists and the Value is an empty string, then the environment
1204 variable is deleted. If the environment variable exists and the Value is not an empty
1205 string, then the value of the environment variable is changed. If the environment
1206 variable does not exist and the Value is an empty string, there is no action. If the
1207 environment variable does not exist and the Value is a non-empty string, then the
1208 environment variable is created and assigned the specified value.
1210 This is not supported pre-UEFI Shell 2.0.
1212 @param EnvKey The key name of the environment variable.
1213 @param EnvVal The Value of the environment variable
1214 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
1216 @retval EFI_SUCCESS the operation was completed sucessfully
1217 @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
1221 ShellSetEnvironmentVariable (
1222 IN CONST CHAR16
*EnvKey
,
1223 IN CONST CHAR16
*EnvVal
,
1228 // Check for UEFI Shell 2.0 protocols
1230 if (gEfiShellProtocol
!= NULL
) {
1231 return (gEfiShellProtocol
->SetEnv(EnvKey
, EnvVal
, Volatile
));
1235 // This feature does not exist under EFI shell
1237 return (EFI_UNSUPPORTED
);
1241 Cause the shell to parse and execute a command line.
1243 This function creates a nested instance of the shell and executes the specified
1244 command (CommandLine) with the specified environment (Environment). Upon return,
1245 the status code returned by the specified command is placed in StatusCode.
1246 If Environment is NULL, then the current environment is used and all changes made
1247 by the commands executed will be reflected in the current environment. If the
1248 Environment is non-NULL, then the changes made will be discarded.
1249 The CommandLine is executed from the current working directory on the current
1252 The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
1253 environment. The values pointed to by the parameters will be unchanged by the
1254 ShellExecute() function. The Output parameter has no effect in a
1255 UEFI Shell 2.0 environment.
1257 @param[in] ParentHandle The parent image starting the operation.
1258 @param[in] CommandLine The pointer to a NULL terminated command line.
1259 @param[in] Output True to display debug output. False to hide it.
1260 @param[in] EnvironmentVariables Optional pointer to array of environment variables
1261 in the form "x=y". If NULL, the current set is used.
1262 @param[out] Status The status of the run command line.
1264 @retval EFI_SUCCESS The operation completed sucessfully. Status
1265 contains the status code returned.
1266 @retval EFI_INVALID_PARAMETER A parameter contains an invalid value.
1267 @retval EFI_OUT_OF_RESOURCES Out of resources.
1268 @retval EFI_UNSUPPORTED The operation is not allowed.
1273 IN EFI_HANDLE
*ParentHandle
,
1274 IN CHAR16
*CommandLine OPTIONAL
,
1275 IN BOOLEAN Output OPTIONAL
,
1276 IN CHAR16
**EnvironmentVariables OPTIONAL
,
1277 OUT EFI_STATUS
*Status OPTIONAL
1280 EFI_STATUS CmdStatus
;
1282 // Check for UEFI Shell 2.0 protocols
1284 if (gEfiShellProtocol
!= NULL
) {
1286 // Call UEFI Shell 2.0 version (not using Output parameter)
1288 return (gEfiShellProtocol
->Execute(ParentHandle
,
1290 EnvironmentVariables
,
1295 // Check for EFI shell
1297 if (mEfiShellEnvironment2
!= NULL
) {
1299 // Call EFI Shell version.
1300 // Due to oddity in the EFI shell we want to dereference the ParentHandle here
1302 CmdStatus
= (mEfiShellEnvironment2
->Execute(*ParentHandle
,
1306 // No Status output parameter so just use the returned status
1308 if (Status
!= NULL
) {
1309 *Status
= CmdStatus
;
1312 // If there was an error, we can't tell if it was from the command or from
1313 // the Execute() function, so we'll just assume the shell ran successfully
1314 // and the error came from the command.
1319 return (EFI_UNSUPPORTED
);
1323 Retreives the current directory path
1325 If the DeviceName is NULL, it returns the current device's current directory
1326 name. If the DeviceName is not NULL, it returns the current directory name
1329 Note that the current directory string should exclude the tailing backslash character.
1331 @param DeviceName the name of the drive to get directory on
1333 @retval NULL the directory does not exist
1334 @return != NULL the directory
1338 ShellGetCurrentDir (
1339 IN CHAR16
* CONST DeviceName OPTIONAL
1343 // Check for UEFI Shell 2.0 protocols
1345 if (gEfiShellProtocol
!= NULL
) {
1346 return (gEfiShellProtocol
->GetCurDir(DeviceName
));
1350 // Check for EFI shell
1352 if (mEfiShellEnvironment2
!= NULL
) {
1353 return (mEfiShellEnvironment2
->CurDir(DeviceName
));
1359 sets (enabled or disabled) the page break mode
1361 when page break mode is enabled the screen will stop scrolling
1362 and wait for operator input before scrolling a subsequent screen.
1364 @param CurrentState TRUE to enable and FALSE to disable
1368 ShellSetPageBreakMode (
1369 IN BOOLEAN CurrentState
1373 // check for enabling
1375 if (CurrentState
!= 0x00) {
1377 // check for UEFI Shell 2.0
1379 if (gEfiShellProtocol
!= NULL
) {
1381 // Enable with UEFI 2.0 Shell
1383 gEfiShellProtocol
->EnablePageBreak();
1387 // Check for EFI shell
1389 if (mEfiShellEnvironment2
!= NULL
) {
1391 // Enable with EFI Shell
1393 mEfiShellEnvironment2
->EnablePageBreak (DEFAULT_INIT_ROW
, DEFAULT_AUTO_LF
);
1399 // check for UEFI Shell 2.0
1401 if (gEfiShellProtocol
!= NULL
) {
1403 // Disable with UEFI 2.0 Shell
1405 gEfiShellProtocol
->DisablePageBreak();
1409 // Check for EFI shell
1411 if (mEfiShellEnvironment2
!= NULL
) {
1413 // Disable with EFI Shell
1415 mEfiShellEnvironment2
->DisablePageBreak ();
1423 /// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
1424 /// This allows for the struct to be populated.
1431 SHELL_FILE_HANDLE Handle
;
1432 EFI_FILE_INFO
*Info
;
1433 } EFI_SHELL_FILE_INFO_NO_CONST
;
1436 Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
1438 if OldStyleFileList is NULL then ASSERT()
1440 this function will convert a SHELL_FILE_ARG based list into a callee allocated
1441 EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
1442 the ShellCloseFileMetaArg function.
1444 @param[in] FileList the EFI shell list type
1445 @param[in, out] ListHead the list to add to
1447 @retval the resultant head of the double linked new format list;
1450 InternalShellConvertFileListType (
1451 IN LIST_ENTRY
*FileList
,
1452 IN OUT LIST_ENTRY
*ListHead
1455 SHELL_FILE_ARG
*OldInfo
;
1457 EFI_SHELL_FILE_INFO_NO_CONST
*NewInfo
;
1462 ASSERT(FileList
!= NULL
);
1463 ASSERT(ListHead
!= NULL
);
1466 // enumerate through each member of the old list and copy
1468 for (Link
= FileList
->ForwardLink
; Link
!= FileList
; Link
= Link
->ForwardLink
) {
1469 OldInfo
= CR (Link
, SHELL_FILE_ARG
, Link
, SHELL_FILE_ARG_SIGNATURE
);
1470 ASSERT(OldInfo
!= NULL
);
1473 // Skip ones that failed to open...
1475 if (OldInfo
->Status
!= EFI_SUCCESS
) {
1480 // make sure the old list was valid
1482 ASSERT(OldInfo
->Info
!= NULL
);
1483 ASSERT(OldInfo
->FullName
!= NULL
);
1484 ASSERT(OldInfo
->FileName
!= NULL
);
1487 // allocate a new EFI_SHELL_FILE_INFO object
1489 NewInfo
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1490 if (NewInfo
== NULL
) {
1491 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO
**)(&ListHead
));
1497 // copy the simple items
1499 NewInfo
->Handle
= OldInfo
->Handle
;
1500 NewInfo
->Status
= OldInfo
->Status
;
1502 // old shell checks for 0 not NULL
1503 OldInfo
->Handle
= 0;
1506 // allocate new space to copy strings and structure
1508 NewInfo
->FullName
= AllocateCopyPool(StrSize(OldInfo
->FullName
), OldInfo
->FullName
);
1509 NewInfo
->FileName
= AllocateCopyPool(StrSize(OldInfo
->FileName
), OldInfo
->FileName
);
1510 NewInfo
->Info
= AllocateCopyPool((UINTN
)OldInfo
->Info
->Size
, OldInfo
->Info
);
1513 // make sure all the memory allocations were sucessful
1515 if (NULL
== NewInfo
->FullName
|| NewInfo
->FileName
== NULL
|| NewInfo
->Info
== NULL
) {
1517 // Free the partially allocated new node
1519 SHELL_FREE_NON_NULL(NewInfo
->FullName
);
1520 SHELL_FREE_NON_NULL(NewInfo
->FileName
);
1521 SHELL_FREE_NON_NULL(NewInfo
->Info
);
1522 SHELL_FREE_NON_NULL(NewInfo
);
1525 // Free the previously converted stuff
1527 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO
**)(&ListHead
));
1533 // add that to the list
1535 InsertTailList(ListHead
, &NewInfo
->Link
);
1540 Opens a group of files based on a path.
1542 This function uses the Arg to open all the matching files. Each matched
1543 file has a SHELL_FILE_INFO structure to record the file information. These
1544 structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
1545 structures from ListHead to access each file. This function supports wildcards
1546 and will process '?' and '*' as such. the list must be freed with a call to
1547 ShellCloseFileMetaArg().
1549 If you are NOT appending to an existing list *ListHead must be NULL. If
1550 *ListHead is NULL then it must be callee freed.
1552 @param Arg pointer to path string
1553 @param OpenMode mode to open files with
1554 @param ListHead head of linked list of results
1556 @retval EFI_SUCCESS the operation was sucessful and the list head
1557 contains the list of opened files
1558 @return != EFI_SUCCESS the operation failed
1560 @sa InternalShellConvertFileListType
1564 ShellOpenFileMetaArg (
1567 IN OUT EFI_SHELL_FILE_INFO
**ListHead
1571 LIST_ENTRY mOldStyleFileList
;
1572 CHAR16
*CleanFilePathStr
;
1575 // ASSERT that Arg and ListHead are not NULL
1577 ASSERT(Arg
!= NULL
);
1578 ASSERT(ListHead
!= NULL
);
1580 CleanFilePathStr
= NULL
;
1582 Status
= InternalShellStripQuotes (Arg
, &CleanFilePathStr
);
1583 if (EFI_ERROR (Status
)) {
1588 // Check for UEFI Shell 2.0 protocols
1590 if (gEfiShellProtocol
!= NULL
) {
1591 if (*ListHead
== NULL
) {
1592 *ListHead
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1593 if (*ListHead
== NULL
) {
1594 FreePool(CleanFilePathStr
);
1595 return (EFI_OUT_OF_RESOURCES
);
1597 InitializeListHead(&((*ListHead
)->Link
));
1599 Status
= gEfiShellProtocol
->OpenFileList(CleanFilePathStr
,
1602 if (EFI_ERROR(Status
)) {
1603 gEfiShellProtocol
->RemoveDupInFileList(ListHead
);
1605 Status
= gEfiShellProtocol
->RemoveDupInFileList(ListHead
);
1607 if (*ListHead
!= NULL
&& IsListEmpty(&(*ListHead
)->Link
)) {
1608 FreePool(*ListHead
);
1609 FreePool(CleanFilePathStr
);
1611 return (EFI_NOT_FOUND
);
1613 FreePool(CleanFilePathStr
);
1618 // Check for EFI shell
1620 if (mEfiShellEnvironment2
!= NULL
) {
1622 // make sure the list head is initialized
1624 InitializeListHead(&mOldStyleFileList
);
1627 // Get the EFI Shell list of files
1629 Status
= mEfiShellEnvironment2
->FileMetaArg(CleanFilePathStr
, &mOldStyleFileList
);
1630 if (EFI_ERROR(Status
)) {
1632 FreePool(CleanFilePathStr
);
1636 if (*ListHead
== NULL
) {
1637 *ListHead
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1638 if (*ListHead
== NULL
) {
1639 FreePool(CleanFilePathStr
);
1640 return (EFI_OUT_OF_RESOURCES
);
1642 InitializeListHead(&((*ListHead
)->Link
));
1646 // Convert that to equivalent of UEFI Shell 2.0 structure
1648 InternalShellConvertFileListType(&mOldStyleFileList
, &(*ListHead
)->Link
);
1651 // Free the EFI Shell version that was converted.
1653 mEfiShellEnvironment2
->FreeFileList(&mOldStyleFileList
);
1655 if ((*ListHead
)->Link
.ForwardLink
== (*ListHead
)->Link
.BackLink
&& (*ListHead
)->Link
.BackLink
== &((*ListHead
)->Link
)) {
1656 FreePool(*ListHead
);
1658 Status
= EFI_NOT_FOUND
;
1660 FreePool(CleanFilePathStr
);
1664 FreePool(CleanFilePathStr
);
1665 return (EFI_UNSUPPORTED
);
1668 Free the linked list returned from ShellOpenFileMetaArg.
1670 if ListHead is NULL then ASSERT().
1672 @param ListHead the pointer to free.
1674 @retval EFI_SUCCESS the operation was sucessful.
1678 ShellCloseFileMetaArg (
1679 IN OUT EFI_SHELL_FILE_INFO
**ListHead
1685 // ASSERT that ListHead is not NULL
1687 ASSERT(ListHead
!= NULL
);
1690 // Check for UEFI Shell 2.0 protocols
1692 if (gEfiShellProtocol
!= NULL
) {
1693 return (gEfiShellProtocol
->FreeFileList(ListHead
));
1694 } else if (mEfiShellEnvironment2
!= NULL
) {
1696 // Since this is EFI Shell version we need to free our internally made copy
1699 for ( Node
= GetFirstNode(&(*ListHead
)->Link
)
1700 ; *ListHead
!= NULL
&& !IsListEmpty(&(*ListHead
)->Link
)
1701 ; Node
= GetFirstNode(&(*ListHead
)->Link
)) {
1702 RemoveEntryList(Node
);
1703 ((EFI_FILE_PROTOCOL
*)((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->Handle
)->Close(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->Handle
);
1704 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->FullName
);
1705 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->FileName
);
1706 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->Info
);
1707 FreePool((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
);
1709 SHELL_FREE_NON_NULL(*ListHead
);
1713 return (EFI_UNSUPPORTED
);
1717 Find a file by searching the CWD and then the path.
1719 If FileName is NULL then ASSERT.
1721 If the return value is not NULL then the memory must be caller freed.
1723 @param FileName Filename string.
1725 @retval NULL the file was not found
1726 @return !NULL the full path to the file.
1731 IN CONST CHAR16
*FileName
1735 SHELL_FILE_HANDLE Handle
;
1739 CONST CHAR16
*Walker
;
1746 // First make sure its not an absolute path.
1748 Status
= ShellOpenFileByName(FileName
, &Handle
, EFI_FILE_MODE_READ
, 0);
1749 if (!EFI_ERROR(Status
)){
1750 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
1751 ASSERT(RetVal
== NULL
);
1752 RetVal
= StrnCatGrow(&RetVal
, NULL
, FileName
, 0);
1753 ShellCloseFile(&Handle
);
1756 ShellCloseFile(&Handle
);
1760 Path
= ShellGetEnvironmentVariable(L
"cwd");
1762 Size
= StrSize(Path
) + sizeof(CHAR16
);
1763 Size
+= StrSize(FileName
);
1764 TestPath
= AllocateZeroPool(Size
);
1765 if (TestPath
== NULL
) {
1768 StrCpyS(TestPath
, Size
/sizeof(CHAR16
), Path
);
1769 StrCatS(TestPath
, Size
/sizeof(CHAR16
), L
"\\");
1770 StrCatS(TestPath
, Size
/sizeof(CHAR16
), FileName
);
1771 Status
= ShellOpenFileByName(TestPath
, &Handle
, EFI_FILE_MODE_READ
, 0);
1772 if (!EFI_ERROR(Status
)){
1773 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
1774 ASSERT(RetVal
== NULL
);
1775 RetVal
= StrnCatGrow(&RetVal
, NULL
, TestPath
, 0);
1776 ShellCloseFile(&Handle
);
1780 ShellCloseFile(&Handle
);
1785 Path
= ShellGetEnvironmentVariable(L
"path");
1787 Size
= StrSize(Path
)+sizeof(CHAR16
);
1788 Size
+= StrSize(FileName
);
1789 TestPath
= AllocateZeroPool(Size
);
1790 if (TestPath
== NULL
) {
1793 Walker
= (CHAR16
*)Path
;
1795 CopyMem(TestPath
, Walker
, StrSize(Walker
));
1796 if (TestPath
!= NULL
) {
1797 TempChar
= StrStr(TestPath
, L
";");
1798 if (TempChar
!= NULL
) {
1799 *TempChar
= CHAR_NULL
;
1801 if (TestPath
[StrLen(TestPath
)-1] != L
'\\') {
1802 StrCatS(TestPath
, Size
/sizeof(CHAR16
), L
"\\");
1804 if (FileName
[0] == L
'\\') {
1807 StrCatS(TestPath
, Size
/sizeof(CHAR16
), FileName
);
1808 if (StrStr(Walker
, L
";") != NULL
) {
1809 Walker
= StrStr(Walker
, L
";") + 1;
1813 Status
= ShellOpenFileByName(TestPath
, &Handle
, EFI_FILE_MODE_READ
, 0);
1814 if (!EFI_ERROR(Status
)){
1815 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
1816 ASSERT(RetVal
== NULL
);
1817 RetVal
= StrnCatGrow(&RetVal
, NULL
, TestPath
, 0);
1818 ShellCloseFile(&Handle
);
1821 ShellCloseFile(&Handle
);
1825 } while (Walker
!= NULL
&& Walker
[0] != CHAR_NULL
);
1832 Find a file by searching the CWD and then the path with a variable set of file
1833 extensions. If the file is not found it will append each extension in the list
1834 in the order provided and return the first one that is successful.
1836 If FileName is NULL, then ASSERT.
1837 If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
1839 If the return value is not NULL then the memory must be caller freed.
1841 @param[in] FileName Filename string.
1842 @param[in] FileExtension Semi-colon delimeted list of possible extensions.
1844 @retval NULL The file was not found.
1845 @retval !NULL The path to the file.
1849 ShellFindFilePathEx (
1850 IN CONST CHAR16
*FileName
,
1851 IN CONST CHAR16
*FileExtension
1856 CONST CHAR16
*ExtensionWalker
;
1861 ASSERT(FileName
!= NULL
);
1862 if (FileExtension
== NULL
) {
1863 return (ShellFindFilePath(FileName
));
1865 RetVal
= ShellFindFilePath(FileName
);
1866 if (RetVal
!= NULL
) {
1869 Size
= StrSize(FileName
);
1870 Size
+= StrSize(FileExtension
);
1871 TestPath
= AllocateZeroPool(Size
);
1872 if (TestPath
== NULL
) {
1875 for (ExtensionWalker
= FileExtension
, TempChar2
= (CHAR16
*)FileExtension
; TempChar2
!= NULL
; ExtensionWalker
= TempChar2
+ 1){
1876 StrCpyS(TestPath
, Size
/sizeof(CHAR16
), FileName
);
1877 if (ExtensionWalker
!= NULL
) {
1878 StrCatS(TestPath
, Size
/sizeof(CHAR16
), ExtensionWalker
);
1880 TempChar
= StrStr(TestPath
, L
";");
1881 if (TempChar
!= NULL
) {
1882 *TempChar
= CHAR_NULL
;
1884 RetVal
= ShellFindFilePath(TestPath
);
1885 if (RetVal
!= NULL
) {
1888 ASSERT(ExtensionWalker
!= NULL
);
1889 TempChar2
= StrStr(ExtensionWalker
, L
";");
1898 SHELL_PARAM_TYPE Type
;
1900 UINTN OriginalPosition
;
1901 } SHELL_PARAM_PACKAGE
;
1904 Checks the list of valid arguments and returns TRUE if the item was found. If the
1905 return value is TRUE then the type parameter is set also.
1907 if CheckList is NULL then ASSERT();
1908 if Name is NULL then ASSERT();
1909 if Type is NULL then ASSERT();
1911 @param Name pointer to Name of parameter found
1912 @param CheckList List to check against
1913 @param Type pointer to type of parameter if it was found
1915 @retval TRUE the Parameter was found. Type is valid.
1916 @retval FALSE the Parameter was not found. Type is not valid.
1919 InternalIsOnCheckList (
1920 IN CONST CHAR16
*Name
,
1921 IN CONST SHELL_PARAM_ITEM
*CheckList
,
1922 OUT SHELL_PARAM_TYPE
*Type
1925 SHELL_PARAM_ITEM
*TempListItem
;
1929 // ASSERT that all 3 pointer parameters aren't NULL
1931 ASSERT(CheckList
!= NULL
);
1932 ASSERT(Type
!= NULL
);
1933 ASSERT(Name
!= NULL
);
1936 // question mark and page break mode are always supported
1938 if ((StrCmp(Name
, L
"-?") == 0) ||
1939 (StrCmp(Name
, L
"-b") == 0)
1946 // Enumerate through the list
1948 for (TempListItem
= (SHELL_PARAM_ITEM
*)CheckList
; TempListItem
->Name
!= NULL
; TempListItem
++) {
1950 // If the Type is TypeStart only check the first characters of the passed in param
1951 // If it matches set the type and return TRUE
1953 if (TempListItem
->Type
== TypeStart
) {
1954 if (StrnCmp(Name
, TempListItem
->Name
, StrLen(TempListItem
->Name
)) == 0) {
1955 *Type
= TempListItem
->Type
;
1959 TempString
= StrnCatGrow(&TempString
, NULL
, Name
, StrLen(TempListItem
->Name
));
1960 if (TempString
!= NULL
) {
1961 if (StringNoCaseCompare(&TempString
, &TempListItem
->Name
) == 0) {
1962 *Type
= TempListItem
->Type
;
1963 FreePool(TempString
);
1966 FreePool(TempString
);
1968 } else if (StringNoCaseCompare(&Name
, &TempListItem
->Name
) == 0) {
1969 *Type
= TempListItem
->Type
;
1977 Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'
1979 @param[in] Name pointer to Name of parameter found
1980 @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
1981 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
1983 @retval TRUE the Parameter is a flag.
1984 @retval FALSE the Parameter not a flag.
1988 IN CONST CHAR16
*Name
,
1989 IN CONST BOOLEAN AlwaysAllowNumbers
,
1990 IN CONST BOOLEAN TimeNumbers
1994 // ASSERT that Name isn't NULL
1996 ASSERT(Name
!= NULL
);
1999 // If we accept numbers then dont return TRUE. (they will be values)
2001 if (((Name
[0] == L
'-' || Name
[0] == L
'+') && InternalShellIsHexOrDecimalNumber(Name
+1, FALSE
, FALSE
, TimeNumbers
)) && AlwaysAllowNumbers
) {
2006 // If the Name has a /, +, or - as the first character return TRUE
2008 if ((Name
[0] == L
'/') ||
2009 (Name
[0] == L
'-') ||
2018 Checks the command line arguments passed against the list of valid ones.
2020 If no initialization is required, then return RETURN_SUCCESS.
2022 @param[in] CheckList pointer to list of parameters to check
2023 @param[out] CheckPackage pointer to pointer to list checked values
2024 @param[out] ProblemParam optional pointer to pointer to unicode string for
2025 the paramater that caused failure. If used then the
2026 caller is responsible for freeing the memory.
2027 @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
2028 @param[in] Argv pointer to array of parameters
2029 @param[in] Argc Count of parameters in Argv
2030 @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
2032 @retval EFI_SUCCESS The operation completed sucessfully.
2033 @retval EFI_OUT_OF_RESOURCES A memory allocation failed
2034 @retval EFI_INVALID_PARAMETER A parameter was invalid
2035 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
2036 duplicated. the duplicated command line argument
2037 was returned in ProblemParam if provided.
2038 @retval EFI_NOT_FOUND a argument required a value that was missing.
2039 the invalid command line argument was returned in
2040 ProblemParam if provided.
2043 InternalCommandLineParse (
2044 IN CONST SHELL_PARAM_ITEM
*CheckList
,
2045 OUT LIST_ENTRY
**CheckPackage
,
2046 OUT CHAR16
**ProblemParam OPTIONAL
,
2047 IN BOOLEAN AutoPageBreak
,
2048 IN CONST CHAR16
**Argv
,
2050 IN BOOLEAN AlwaysAllowNumbers
2054 SHELL_PARAM_TYPE CurrentItemType
;
2055 SHELL_PARAM_PACKAGE
*CurrentItemPackage
;
2059 CONST CHAR16
*TempPointer
;
2060 UINTN CurrentValueSize
;
2063 CurrentItemPackage
= NULL
;
2069 // If there is only 1 item we dont need to do anything
2072 *CheckPackage
= NULL
;
2073 return (EFI_SUCCESS
);
2079 ASSERT(CheckList
!= NULL
);
2080 ASSERT(Argv
!= NULL
);
2083 // initialize the linked list
2085 *CheckPackage
= (LIST_ENTRY
*)AllocateZeroPool(sizeof(LIST_ENTRY
));
2086 if (*CheckPackage
== NULL
) {
2087 return (EFI_OUT_OF_RESOURCES
);
2090 InitializeListHead(*CheckPackage
);
2093 // loop through each of the arguments
2095 for (LoopCounter
= 0 ; LoopCounter
< Argc
; ++LoopCounter
) {
2096 if (Argv
[LoopCounter
] == NULL
) {
2098 // do nothing for NULL argv
2100 } else if (InternalIsOnCheckList(Argv
[LoopCounter
], CheckList
, &CurrentItemType
)) {
2102 // We might have leftover if last parameter didnt have optional value
2104 if (GetItemValue
!= 0) {
2106 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2111 CurrentItemPackage
= AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE
));
2112 if (CurrentItemPackage
== NULL
) {
2113 ShellCommandLineFreeVarList(*CheckPackage
);
2114 *CheckPackage
= NULL
;
2115 return (EFI_OUT_OF_RESOURCES
);
2117 CurrentItemPackage
->Name
= AllocateCopyPool(StrSize(Argv
[LoopCounter
]), Argv
[LoopCounter
]);
2118 if (CurrentItemPackage
->Name
== NULL
) {
2119 ShellCommandLineFreeVarList(*CheckPackage
);
2120 *CheckPackage
= NULL
;
2121 return (EFI_OUT_OF_RESOURCES
);
2123 CurrentItemPackage
->Type
= CurrentItemType
;
2124 CurrentItemPackage
->OriginalPosition
= (UINTN
)(-1);
2125 CurrentItemPackage
->Value
= NULL
;
2128 // Does this flag require a value
2130 switch (CurrentItemPackage
->Type
) {
2132 // possibly trigger the next loop(s) to populate the value of this item
2139 case TypeDoubleValue
:
2144 GetItemValue
= (UINTN
)(-1);
2149 // this item has no value expected; we are done
2151 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2152 ASSERT(GetItemValue
== 0);
2155 } else if (GetItemValue
!= 0 && CurrentItemPackage
!= NULL
&& !InternalIsFlag(Argv
[LoopCounter
], AlwaysAllowNumbers
, (BOOLEAN
)(CurrentItemPackage
->Type
== TypeTimeValue
))) {
2157 // get the item VALUE for a previous flag
2159 CurrentValueSize
= ValueSize
+ StrSize(Argv
[LoopCounter
]) + sizeof(CHAR16
);
2160 NewValue
= ReallocatePool(ValueSize
, CurrentValueSize
, CurrentItemPackage
->Value
);
2161 if (NewValue
== NULL
) {
2162 SHELL_FREE_NON_NULL (CurrentItemPackage
->Value
);
2163 SHELL_FREE_NON_NULL (CurrentItemPackage
);
2164 ShellCommandLineFreeVarList (*CheckPackage
);
2165 *CheckPackage
= NULL
;
2166 return EFI_OUT_OF_RESOURCES
;
2168 CurrentItemPackage
->Value
= NewValue
;
2169 if (ValueSize
== 0) {
2170 StrCpyS( CurrentItemPackage
->Value
,
2171 CurrentValueSize
/sizeof(CHAR16
),
2175 StrCatS( CurrentItemPackage
->Value
,
2176 CurrentValueSize
/sizeof(CHAR16
),
2179 StrCatS( CurrentItemPackage
->Value
,
2180 CurrentValueSize
/sizeof(CHAR16
),
2184 ValueSize
+= StrSize(Argv
[LoopCounter
]) + sizeof(CHAR16
);
2187 if (GetItemValue
== 0) {
2188 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2190 } else if (!InternalIsFlag(Argv
[LoopCounter
], AlwaysAllowNumbers
, FALSE
)){
2192 // add this one as a non-flag
2195 TempPointer
= Argv
[LoopCounter
];
2196 if ((*TempPointer
== L
'^' && *(TempPointer
+1) == L
'-')
2197 || (*TempPointer
== L
'^' && *(TempPointer
+1) == L
'/')
2198 || (*TempPointer
== L
'^' && *(TempPointer
+1) == L
'+')
2202 CurrentItemPackage
= AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE
));
2203 if (CurrentItemPackage
== NULL
) {
2204 ShellCommandLineFreeVarList(*CheckPackage
);
2205 *CheckPackage
= NULL
;
2206 return (EFI_OUT_OF_RESOURCES
);
2208 CurrentItemPackage
->Name
= NULL
;
2209 CurrentItemPackage
->Type
= TypePosition
;
2210 CurrentItemPackage
->Value
= AllocateCopyPool(StrSize(TempPointer
), TempPointer
);
2211 if (CurrentItemPackage
->Value
== NULL
) {
2212 ShellCommandLineFreeVarList(*CheckPackage
);
2213 *CheckPackage
= NULL
;
2214 return (EFI_OUT_OF_RESOURCES
);
2216 CurrentItemPackage
->OriginalPosition
= Count
++;
2217 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2220 // this was a non-recognised flag... error!
2222 if (ProblemParam
!= NULL
) {
2223 *ProblemParam
= AllocateCopyPool(StrSize(Argv
[LoopCounter
]), Argv
[LoopCounter
]);
2225 ShellCommandLineFreeVarList(*CheckPackage
);
2226 *CheckPackage
= NULL
;
2227 return (EFI_VOLUME_CORRUPTED
);
2230 if (GetItemValue
!= 0) {
2232 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2235 // support for AutoPageBreak
2237 if (AutoPageBreak
&& ShellCommandLineGetFlag(*CheckPackage
, L
"-b")) {
2238 ShellSetPageBreakMode(TRUE
);
2240 return (EFI_SUCCESS
);
2244 Checks the command line arguments passed against the list of valid ones.
2245 Optionally removes NULL values first.
2247 If no initialization is required, then return RETURN_SUCCESS.
2249 @param[in] CheckList The pointer to list of parameters to check.
2250 @param[out] CheckPackage The package of checked values.
2251 @param[out] ProblemParam Optional pointer to pointer to unicode string for
2252 the paramater that caused failure.
2253 @param[in] AutoPageBreak Will automatically set PageBreakEnabled.
2254 @param[in] AlwaysAllowNumbers Will never fail for number based flags.
2256 @retval EFI_SUCCESS The operation completed sucessfully.
2257 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2258 @retval EFI_INVALID_PARAMETER A parameter was invalid.
2259 @retval EFI_VOLUME_CORRUPTED The command line was corrupt.
2260 @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One
2261 of the command line arguments was returned in
2262 ProblemParam if provided.
2263 @retval EFI_NOT_FOUND A argument required a value that was missing.
2264 The invalid command line argument was returned in
2265 ProblemParam if provided.
2269 ShellCommandLineParseEx (
2270 IN CONST SHELL_PARAM_ITEM
*CheckList
,
2271 OUT LIST_ENTRY
**CheckPackage
,
2272 OUT CHAR16
**ProblemParam OPTIONAL
,
2273 IN BOOLEAN AutoPageBreak
,
2274 IN BOOLEAN AlwaysAllowNumbers
2278 // ASSERT that CheckList and CheckPackage aren't NULL
2280 ASSERT(CheckList
!= NULL
);
2281 ASSERT(CheckPackage
!= NULL
);
2284 // Check for UEFI Shell 2.0 protocols
2286 if (gEfiShellParametersProtocol
!= NULL
) {
2287 return (InternalCommandLineParse(CheckList
,
2291 (CONST CHAR16
**) gEfiShellParametersProtocol
->Argv
,
2292 gEfiShellParametersProtocol
->Argc
,
2293 AlwaysAllowNumbers
));
2297 // ASSERT That EFI Shell is not required
2299 ASSERT (mEfiShellInterface
!= NULL
);
2300 return (InternalCommandLineParse(CheckList
,
2304 (CONST CHAR16
**) mEfiShellInterface
->Argv
,
2305 mEfiShellInterface
->Argc
,
2306 AlwaysAllowNumbers
));
2310 Frees shell variable list that was returned from ShellCommandLineParse.
2312 This function will free all the memory that was used for the CheckPackage
2313 list of postprocessed shell arguments.
2315 this function has no return value.
2317 if CheckPackage is NULL, then return
2319 @param CheckPackage the list to de-allocate
2323 ShellCommandLineFreeVarList (
2324 IN LIST_ENTRY
*CheckPackage
2330 // check for CheckPackage == NULL
2332 if (CheckPackage
== NULL
) {
2337 // for each node in the list
2339 for ( Node
= GetFirstNode(CheckPackage
)
2340 ; !IsListEmpty(CheckPackage
)
2341 ; Node
= GetFirstNode(CheckPackage
)
2344 // Remove it from the list
2346 RemoveEntryList(Node
);
2349 // if it has a name free the name
2351 if (((SHELL_PARAM_PACKAGE
*)Node
)->Name
!= NULL
) {
2352 FreePool(((SHELL_PARAM_PACKAGE
*)Node
)->Name
);
2356 // if it has a value free the value
2358 if (((SHELL_PARAM_PACKAGE
*)Node
)->Value
!= NULL
) {
2359 FreePool(((SHELL_PARAM_PACKAGE
*)Node
)->Value
);
2363 // free the node structure
2365 FreePool((SHELL_PARAM_PACKAGE
*)Node
);
2368 // free the list head node
2370 FreePool(CheckPackage
);
2373 Checks for presence of a flag parameter
2375 flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
2377 if CheckPackage is NULL then return FALSE.
2378 if KeyString is NULL then ASSERT()
2380 @param CheckPackage The package of parsed command line arguments
2381 @param KeyString the Key of the command line argument to check for
2383 @retval TRUE the flag is on the command line
2384 @retval FALSE the flag is not on the command line
2388 ShellCommandLineGetFlag (
2389 IN CONST LIST_ENTRY
* CONST CheckPackage
,
2390 IN CONST CHAR16
* CONST KeyString
2397 // return FALSE for no package or KeyString is NULL
2399 if (CheckPackage
== NULL
|| KeyString
== NULL
) {
2404 // enumerate through the list of parametrs
2406 for ( Node
= GetFirstNode(CheckPackage
)
2407 ; !IsNull (CheckPackage
, Node
)
2408 ; Node
= GetNextNode(CheckPackage
, Node
)
2411 // If the Name matches, return TRUE (and there may be NULL name)
2413 if (((SHELL_PARAM_PACKAGE
*)Node
)->Name
!= NULL
) {
2415 // If Type is TypeStart then only compare the begining of the strings
2417 if (((SHELL_PARAM_PACKAGE
*)Node
)->Type
== TypeStart
) {
2418 if (StrnCmp(KeyString
, ((SHELL_PARAM_PACKAGE
*)Node
)->Name
, StrLen(KeyString
)) == 0) {
2422 TempString
= StrnCatGrow(&TempString
, NULL
, KeyString
, StrLen(((SHELL_PARAM_PACKAGE
*)Node
)->Name
));
2423 if (TempString
!= NULL
) {
2424 if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2425 FreePool(TempString
);
2428 FreePool(TempString
);
2430 } else if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2438 Returns value from command line argument.
2440 Value parameters are in the form of "-<Key> value" or "/<Key> value".
2442 If CheckPackage is NULL, then return NULL.
2444 @param[in] CheckPackage The package of parsed command line arguments.
2445 @param[in] KeyString The Key of the command line argument to check for.
2447 @retval NULL The flag is not on the command line.
2448 @retval !=NULL The pointer to unicode string of the value.
2452 ShellCommandLineGetValue (
2453 IN CONST LIST_ENTRY
*CheckPackage
,
2454 IN CHAR16
*KeyString
2461 // return NULL for no package or KeyString is NULL
2463 if (CheckPackage
== NULL
|| KeyString
== NULL
) {
2468 // enumerate through the list of parametrs
2470 for ( Node
= GetFirstNode(CheckPackage
)
2471 ; !IsNull (CheckPackage
, Node
)
2472 ; Node
= GetNextNode(CheckPackage
, Node
)
2475 // If the Name matches, return TRUE (and there may be NULL name)
2477 if (((SHELL_PARAM_PACKAGE
*)Node
)->Name
!= NULL
) {
2479 // If Type is TypeStart then only compare the begining of the strings
2481 if (((SHELL_PARAM_PACKAGE
*)Node
)->Type
== TypeStart
) {
2482 if (StrnCmp(KeyString
, ((SHELL_PARAM_PACKAGE
*)Node
)->Name
, StrLen(KeyString
)) == 0) {
2483 return (((SHELL_PARAM_PACKAGE
*)Node
)->Name
+ StrLen(KeyString
));
2486 TempString
= StrnCatGrow(&TempString
, NULL
, KeyString
, StrLen(((SHELL_PARAM_PACKAGE
*)Node
)->Name
));
2487 if (TempString
!= NULL
) {
2488 if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2489 FreePool(TempString
);
2490 return (((SHELL_PARAM_PACKAGE
*)Node
)->Name
+ StrLen(KeyString
));
2492 FreePool(TempString
);
2494 } else if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2495 return (((SHELL_PARAM_PACKAGE
*)Node
)->Value
);
2503 Returns raw value from command line argument.
2505 Raw value parameters are in the form of "value" in a specific position in the list.
2507 If CheckPackage is NULL, then return NULL.
2509 @param[in] CheckPackage The package of parsed command line arguments.
2510 @param[in] Position The position of the value.
2512 @retval NULL The flag is not on the command line.
2513 @retval !=NULL The pointer to unicode string of the value.
2517 ShellCommandLineGetRawValue (
2518 IN CONST LIST_ENTRY
* CONST CheckPackage
,
2525 // check for CheckPackage == NULL
2527 if (CheckPackage
== NULL
) {
2532 // enumerate through the list of parametrs
2534 for ( Node
= GetFirstNode(CheckPackage
)
2535 ; !IsNull (CheckPackage
, Node
)
2536 ; Node
= GetNextNode(CheckPackage
, Node
)
2539 // If the position matches, return the value
2541 if (((SHELL_PARAM_PACKAGE
*)Node
)->OriginalPosition
== Position
) {
2542 return (((SHELL_PARAM_PACKAGE
*)Node
)->Value
);
2549 returns the number of command line value parameters that were parsed.
2551 this will not include flags.
2553 @param[in] CheckPackage The package of parsed command line arguments.
2555 @retval (UINTN)-1 No parsing has ocurred
2556 @return other The number of value parameters found
2560 ShellCommandLineGetCount(
2561 IN CONST LIST_ENTRY
*CheckPackage
2567 if (CheckPackage
== NULL
) {
2570 for ( Node1
= GetFirstNode(CheckPackage
), Count
= 0
2571 ; !IsNull (CheckPackage
, Node1
)
2572 ; Node1
= GetNextNode(CheckPackage
, Node1
)
2574 if (((SHELL_PARAM_PACKAGE
*)Node1
)->Name
== NULL
) {
2582 Determines if a parameter is duplicated.
2584 If Param is not NULL then it will point to a callee allocated string buffer
2585 with the parameter value if a duplicate is found.
2587 If CheckPackage is NULL, then ASSERT.
2589 @param[in] CheckPackage The package of parsed command line arguments.
2590 @param[out] Param Upon finding one, a pointer to the duplicated parameter.
2592 @retval EFI_SUCCESS No parameters were duplicated.
2593 @retval EFI_DEVICE_ERROR A duplicate was found.
2597 ShellCommandLineCheckDuplicate (
2598 IN CONST LIST_ENTRY
*CheckPackage
,
2605 ASSERT(CheckPackage
!= NULL
);
2607 for ( Node1
= GetFirstNode(CheckPackage
)
2608 ; !IsNull (CheckPackage
, Node1
)
2609 ; Node1
= GetNextNode(CheckPackage
, Node1
)
2611 for ( Node2
= GetNextNode(CheckPackage
, Node1
)
2612 ; !IsNull (CheckPackage
, Node2
)
2613 ; Node2
= GetNextNode(CheckPackage
, Node2
)
2615 if ((((SHELL_PARAM_PACKAGE
*)Node1
)->Name
!= NULL
) && (((SHELL_PARAM_PACKAGE
*)Node2
)->Name
!= NULL
) && StrCmp(((SHELL_PARAM_PACKAGE
*)Node1
)->Name
, ((SHELL_PARAM_PACKAGE
*)Node2
)->Name
) == 0) {
2616 if (Param
!= NULL
) {
2618 *Param
= StrnCatGrow(Param
, NULL
, ((SHELL_PARAM_PACKAGE
*)Node1
)->Name
, 0);
2620 return (EFI_DEVICE_ERROR
);
2624 return (EFI_SUCCESS
);
2628 This is a find and replace function. Upon successful return the NewString is a copy of
2629 SourceString with each instance of FindTarget replaced with ReplaceWith.
2631 If SourceString and NewString overlap the behavior is undefined.
2633 If the string would grow bigger than NewSize it will halt and return error.
2635 @param[in] SourceString The string with source buffer.
2636 @param[in, out] NewString The string with resultant buffer.
2637 @param[in] NewSize The size in bytes of NewString.
2638 @param[in] FindTarget The string to look for.
2639 @param[in] ReplaceWith The string to replace FindTarget with.
2640 @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'
2641 immediately before it.
2642 @param[in] ParameterReplacing If TRUE will add "" around items with spaces.
2644 @retval EFI_INVALID_PARAMETER SourceString was NULL.
2645 @retval EFI_INVALID_PARAMETER NewString was NULL.
2646 @retval EFI_INVALID_PARAMETER FindTarget was NULL.
2647 @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.
2648 @retval EFI_INVALID_PARAMETER FindTarget had length < 1.
2649 @retval EFI_INVALID_PARAMETER SourceString had length < 1.
2650 @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold
2651 the new string (truncation occurred).
2652 @retval EFI_SUCCESS The string was successfully copied with replacement.
2656 ShellCopySearchAndReplace(
2657 IN CHAR16 CONST
*SourceString
,
2658 IN OUT CHAR16
*NewString
,
2660 IN CONST CHAR16
*FindTarget
,
2661 IN CONST CHAR16
*ReplaceWith
,
2662 IN CONST BOOLEAN SkipPreCarrot
,
2663 IN CONST BOOLEAN ParameterReplacing
2669 if ( (SourceString
== NULL
)
2670 || (NewString
== NULL
)
2671 || (FindTarget
== NULL
)
2672 || (ReplaceWith
== NULL
)
2673 || (StrLen(FindTarget
) < 1)
2674 || (StrLen(SourceString
) < 1)
2676 return (EFI_INVALID_PARAMETER
);
2679 if (StrStr(ReplaceWith
, L
" ") == NULL
|| !ParameterReplacing
) {
2680 Replace
= StrnCatGrow(&Replace
, NULL
, ReplaceWith
, 0);
2682 Replace
= AllocateZeroPool(StrSize(ReplaceWith
) + 2*sizeof(CHAR16
));
2683 if (Replace
!= NULL
) {
2684 UnicodeSPrint(Replace
, StrSize(ReplaceWith
) + 2*sizeof(CHAR16
), L
"\"%s\"", ReplaceWith
);
2687 if (Replace
== NULL
) {
2688 return (EFI_OUT_OF_RESOURCES
);
2690 NewString
= ZeroMem(NewString
, NewSize
);
2691 while (*SourceString
!= CHAR_NULL
) {
2693 // if we find the FindTarget and either Skip == FALSE or Skip and we
2694 // dont have a carrot do a replace...
2696 if (StrnCmp(SourceString
, FindTarget
, StrLen(FindTarget
)) == 0
2697 && ((SkipPreCarrot
&& *(SourceString
-1) != L
'^') || !SkipPreCarrot
)
2699 SourceString
+= StrLen(FindTarget
);
2700 Size
= StrSize(NewString
);
2701 if ((Size
+ (StrLen(Replace
)*sizeof(CHAR16
))) > NewSize
) {
2703 return (EFI_BUFFER_TOO_SMALL
);
2705 StrCatS(NewString
, NewSize
/sizeof(CHAR16
), Replace
);
2707 Size
= StrSize(NewString
);
2708 if (Size
+ sizeof(CHAR16
) > NewSize
) {
2710 return (EFI_BUFFER_TOO_SMALL
);
2712 StrnCatS(NewString
, NewSize
/sizeof(CHAR16
), SourceString
, 1);
2717 return (EFI_SUCCESS
);
2721 Internal worker function to output a string.
2723 This function will output a string to the correct StdOut.
2725 @param[in] String The string to print out.
2727 @retval EFI_SUCCESS The operation was sucessful.
2728 @retval !EFI_SUCCESS The operation failed.
2732 IN CONST CHAR16
*String
2736 Size
= StrSize(String
) - sizeof(CHAR16
);
2738 return (EFI_SUCCESS
);
2740 if (gEfiShellParametersProtocol
!= NULL
) {
2741 return (gEfiShellProtocol
->WriteFile(gEfiShellParametersProtocol
->StdOut
, &Size
, (VOID
*)String
));
2743 if (mEfiShellInterface
!= NULL
) {
2744 if (mEfiShellInterface
->RedirArgc
== 0) {
2746 // Divide in half for old shell. Must be string length not size.
2748 Size
/=2; // Divide in half only when no redirection.
2750 return (mEfiShellInterface
->StdOut
->Write(mEfiShellInterface
->StdOut
, &Size
, (VOID
*)String
));
2753 return (EFI_UNSUPPORTED
);
2757 Print at a specific location on the screen.
2759 This function will move the cursor to a given screen location and print the specified string
2761 If -1 is specified for either the Row or Col the current screen location for BOTH
2764 if either Row or Col is out of range for the current console, then ASSERT
2765 if Format is NULL, then ASSERT
2767 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2768 the following additional flags:
2769 %N - Set output attribute to normal
2770 %H - Set output attribute to highlight
2771 %E - Set output attribute to error
2772 %B - Set output attribute to blue color
2773 %V - Set output attribute to green color
2775 Note: The background color is controlled by the shell command cls.
2777 @param[in] Col the column to print at
2778 @param[in] Row the row to print at
2779 @param[in] Format the format string
2780 @param[in] Marker the marker for the variable argument list
2782 @return EFI_SUCCESS The operation was successful.
2783 @return EFI_DEVICE_ERROR The console device reported an error.
2786 InternalShellPrintWorker(
2787 IN INT32 Col OPTIONAL
,
2788 IN INT32 Row OPTIONAL
,
2789 IN CONST CHAR16
*Format
,
2794 CHAR16
*ResumeLocation
;
2795 CHAR16
*FormatWalker
;
2796 UINTN OriginalAttribute
;
2797 CHAR16
*mPostReplaceFormat
;
2798 CHAR16
*mPostReplaceFormat2
;
2800 mPostReplaceFormat
= AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize
));
2801 mPostReplaceFormat2
= AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize
));
2803 if (mPostReplaceFormat
== NULL
|| mPostReplaceFormat2
== NULL
) {
2804 SHELL_FREE_NON_NULL(mPostReplaceFormat
);
2805 SHELL_FREE_NON_NULL(mPostReplaceFormat2
);
2806 return (EFI_OUT_OF_RESOURCES
);
2809 Status
= EFI_SUCCESS
;
2810 OriginalAttribute
= gST
->ConOut
->Mode
->Attribute
;
2813 // Back and forth each time fixing up 1 of our flags...
2815 Status
= ShellCopySearchAndReplace(Format
, mPostReplaceFormat
, PcdGet16 (PcdShellPrintBufferSize
), L
"%N", L
"%%N", FALSE
, FALSE
);
2816 ASSERT_EFI_ERROR(Status
);
2817 Status
= ShellCopySearchAndReplace(mPostReplaceFormat
, mPostReplaceFormat2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%E", L
"%%E", FALSE
, FALSE
);
2818 ASSERT_EFI_ERROR(Status
);
2819 Status
= ShellCopySearchAndReplace(mPostReplaceFormat2
, mPostReplaceFormat
, PcdGet16 (PcdShellPrintBufferSize
), L
"%H", L
"%%H", FALSE
, FALSE
);
2820 ASSERT_EFI_ERROR(Status
);
2821 Status
= ShellCopySearchAndReplace(mPostReplaceFormat
, mPostReplaceFormat2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%B", L
"%%B", FALSE
, FALSE
);
2822 ASSERT_EFI_ERROR(Status
);
2823 Status
= ShellCopySearchAndReplace(mPostReplaceFormat2
, mPostReplaceFormat
, PcdGet16 (PcdShellPrintBufferSize
), L
"%V", L
"%%V", FALSE
, FALSE
);
2824 ASSERT_EFI_ERROR(Status
);
2827 // Use the last buffer from replacing to print from...
2829 UnicodeVSPrint (mPostReplaceFormat2
, PcdGet16 (PcdShellPrintBufferSize
), mPostReplaceFormat
, Marker
);
2831 if (Col
!= -1 && Row
!= -1) {
2832 Status
= gST
->ConOut
->SetCursorPosition(gST
->ConOut
, Col
, Row
);
2835 FormatWalker
= mPostReplaceFormat2
;
2836 while (*FormatWalker
!= CHAR_NULL
) {
2838 // Find the next attribute change request
2840 ResumeLocation
= StrStr(FormatWalker
, L
"%");
2841 if (ResumeLocation
!= NULL
) {
2842 *ResumeLocation
= CHAR_NULL
;
2845 // print the current FormatWalker string
2847 if (StrLen(FormatWalker
)>0) {
2848 Status
= InternalPrintTo(FormatWalker
);
2849 if (EFI_ERROR(Status
)) {
2855 // update the attribute
2857 if (ResumeLocation
!= NULL
) {
2858 if ((ResumeLocation
!= mPostReplaceFormat2
) && (*(ResumeLocation
-1) == L
'^')) {
2860 // Move cursor back 1 position to overwrite the ^
2862 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gST
->ConOut
->Mode
->CursorColumn
- 1, gST
->ConOut
->Mode
->CursorRow
);
2865 // Print a simple '%' symbol
2867 Status
= InternalPrintTo(L
"%");
2868 ResumeLocation
= ResumeLocation
- 1;
2870 switch (*(ResumeLocation
+1)) {
2872 gST
->ConOut
->SetAttribute(gST
->ConOut
, OriginalAttribute
);
2875 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_YELLOW
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2878 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_WHITE
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2881 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_LIGHTBLUE
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2884 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_LIGHTGREEN
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2888 // Print a simple '%' symbol
2890 Status
= InternalPrintTo(L
"%");
2891 if (EFI_ERROR(Status
)) {
2894 ResumeLocation
= ResumeLocation
- 1;
2900 // reset to normal now...
2906 // update FormatWalker to Resume + 2 (skip the % and the indicator)
2908 FormatWalker
= ResumeLocation
+ 2;
2911 gST
->ConOut
->SetAttribute(gST
->ConOut
, OriginalAttribute
);
2913 SHELL_FREE_NON_NULL(mPostReplaceFormat
);
2914 SHELL_FREE_NON_NULL(mPostReplaceFormat2
);
2919 Print at a specific location on the screen.
2921 This function will move the cursor to a given screen location and print the specified string.
2923 If -1 is specified for either the Row or Col the current screen location for BOTH
2926 If either Row or Col is out of range for the current console, then ASSERT.
2927 If Format is NULL, then ASSERT.
2929 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2930 the following additional flags:
2931 %N - Set output attribute to normal
2932 %H - Set output attribute to highlight
2933 %E - Set output attribute to error
2934 %B - Set output attribute to blue color
2935 %V - Set output attribute to green color
2937 Note: The background color is controlled by the shell command cls.
2939 @param[in] Col the column to print at
2940 @param[in] Row the row to print at
2941 @param[in] Format the format string
2942 @param[in] ... The variable argument list.
2944 @return EFI_SUCCESS The printing was successful.
2945 @return EFI_DEVICE_ERROR The console device reported an error.
2950 IN INT32 Col OPTIONAL
,
2951 IN INT32 Row OPTIONAL
,
2952 IN CONST CHAR16
*Format
,
2958 if (Format
== NULL
) {
2959 return (EFI_INVALID_PARAMETER
);
2961 VA_START (Marker
, Format
);
2962 RetVal
= InternalShellPrintWorker(Col
, Row
, Format
, Marker
);
2968 Print at a specific location on the screen.
2970 This function will move the cursor to a given screen location and print the specified string.
2972 If -1 is specified for either the Row or Col the current screen location for BOTH
2975 If either Row or Col is out of range for the current console, then ASSERT.
2976 If Format is NULL, then ASSERT.
2978 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2979 the following additional flags:
2980 %N - Set output attribute to normal.
2981 %H - Set output attribute to highlight.
2982 %E - Set output attribute to error.
2983 %B - Set output attribute to blue color.
2984 %V - Set output attribute to green color.
2986 Note: The background color is controlled by the shell command cls.
2988 @param[in] Col The column to print at.
2989 @param[in] Row The row to print at.
2990 @param[in] Language The language of the string to retrieve. If this parameter
2991 is NULL, then the current platform language is used.
2992 @param[in] HiiFormatStringId The format string Id for getting from Hii.
2993 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
2994 @param[in] ... The variable argument list.
2996 @return EFI_SUCCESS The printing was successful.
2997 @return EFI_DEVICE_ERROR The console device reported an error.
3002 IN INT32 Col OPTIONAL
,
3003 IN INT32 Row OPTIONAL
,
3004 IN CONST CHAR8
*Language OPTIONAL
,
3005 IN CONST EFI_STRING_ID HiiFormatStringId
,
3006 IN CONST EFI_HANDLE HiiFormatHandle
,
3011 CHAR16
*HiiFormatString
;
3014 RetVal
= EFI_DEVICE_ERROR
;
3016 VA_START (Marker
, HiiFormatHandle
);
3017 HiiFormatString
= HiiGetString(HiiFormatHandle
, HiiFormatStringId
, Language
);
3018 if (HiiFormatString
!= NULL
) {
3019 RetVal
= InternalShellPrintWorker (Col
, Row
, HiiFormatString
, Marker
);
3020 SHELL_FREE_NON_NULL (HiiFormatString
);
3028 Function to determine if a given filename represents a file or a directory.
3030 @param[in] DirName Path to directory to test.
3032 @retval EFI_SUCCESS The Path represents a directory
3033 @retval EFI_NOT_FOUND The Path does not represent a directory
3034 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3035 @return The path failed to open
3040 IN CONST CHAR16
*DirName
3044 SHELL_FILE_HANDLE Handle
;
3045 CHAR16
*TempLocation
;
3046 CHAR16
*TempLocation2
;
3048 ASSERT(DirName
!= NULL
);
3051 TempLocation
= NULL
;
3053 Status
= ShellOpenFileByName(DirName
, &Handle
, EFI_FILE_MODE_READ
, 0);
3054 if (EFI_ERROR(Status
)) {
3056 // try good logic first.
3058 if (gEfiShellProtocol
!= NULL
) {
3059 TempLocation
= StrnCatGrow(&TempLocation
, NULL
, DirName
, 0);
3060 if (TempLocation
== NULL
) {
3061 ShellCloseFile(&Handle
);
3062 return (EFI_OUT_OF_RESOURCES
);
3064 TempLocation2
= StrStr(TempLocation
, L
":");
3065 if (TempLocation2
!= NULL
&& StrLen(StrStr(TempLocation
, L
":")) == 2) {
3066 *(TempLocation2
+1) = CHAR_NULL
;
3068 if (gEfiShellProtocol
->GetDevicePathFromMap(TempLocation
) != NULL
) {
3069 FreePool(TempLocation
);
3070 return (EFI_SUCCESS
);
3072 FreePool(TempLocation
);
3075 // probably a map name?!?!!?
3077 TempLocation
= StrStr(DirName
, L
"\\");
3078 if (TempLocation
!= NULL
&& *(TempLocation
+1) == CHAR_NULL
) {
3079 return (EFI_SUCCESS
);
3085 if (FileHandleIsDirectory(Handle
) == EFI_SUCCESS
) {
3086 ShellCloseFile(&Handle
);
3087 return (EFI_SUCCESS
);
3089 ShellCloseFile(&Handle
);
3090 return (EFI_NOT_FOUND
);
3094 Function to determine if a given filename represents a file.
3096 @param[in] Name Path to file to test.
3098 @retval EFI_SUCCESS The Path represents a file.
3099 @retval EFI_NOT_FOUND The Path does not represent a file.
3100 @retval other The path failed to open.
3105 IN CONST CHAR16
*Name
3109 SHELL_FILE_HANDLE Handle
;
3111 ASSERT(Name
!= NULL
);
3115 Status
= ShellOpenFileByName(Name
, &Handle
, EFI_FILE_MODE_READ
, 0);
3116 if (EFI_ERROR(Status
)) {
3120 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
3121 ShellCloseFile(&Handle
);
3122 return (EFI_SUCCESS
);
3124 ShellCloseFile(&Handle
);
3125 return (EFI_NOT_FOUND
);
3129 Function to determine if a given filename represents a file.
3131 This will search the CWD and then the Path.
3133 If Name is NULL, then ASSERT.
3135 @param[in] Name Path to file to test.
3137 @retval EFI_SUCCESS The Path represents a file.
3138 @retval EFI_NOT_FOUND The Path does not represent a file.
3139 @retval other The path failed to open.
3144 IN CONST CHAR16
*Name
3150 if (!EFI_ERROR(ShellIsFile(Name
))) {
3151 return (EFI_SUCCESS
);
3154 NewName
= ShellFindFilePath(Name
);
3155 if (NewName
== NULL
) {
3156 return (EFI_NOT_FOUND
);
3158 Status
= ShellIsFile(NewName
);
3164 Function return the number converted from a hex representation of a number.
3166 Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
3167 result. Use ShellConvertStringToUint64 instead.
3169 @param[in] String String representation of a number.
3171 @return The unsigned integer result of the conversion.
3172 @retval (UINTN)(-1) An error occured.
3177 IN CONST CHAR16
*String
3182 if (!EFI_ERROR(ShellConvertStringToUint64(String
, &RetVal
, TRUE
, TRUE
))) {
3183 return ((UINTN
)RetVal
);
3186 return ((UINTN
)(-1));
3190 Function to determine whether a string is decimal or hex representation of a number
3191 and return the number converted from the string. Spaces are always skipped.
3193 @param[in] String String representation of a number
3196 @retval (UINTN)(-1) An error ocurred.
3201 IN CONST CHAR16
*String
3209 if (!InternalShellIsHexOrDecimalNumber(String
, Hex
, TRUE
, FALSE
)) {
3213 if (!EFI_ERROR(ShellConvertStringToUint64(String
, &RetVal
, Hex
, TRUE
))) {
3214 return ((UINTN
)RetVal
);
3216 return ((UINTN
)(-1));
3220 Safely append with automatic string resizing given length of Destination and
3221 desired length of copy from Source.
3223 append the first D characters of Source to the end of Destination, where D is
3224 the lesser of Count and the StrLen() of Source. If appending those D characters
3225 will fit within Destination (whose Size is given as CurrentSize) and
3226 still leave room for a NULL terminator, then those characters are appended,
3227 starting at the original terminating NULL of Destination, and a new terminating
3230 If appending D characters onto Destination will result in a overflow of the size
3231 given in CurrentSize the string will be grown such that the copy can be performed
3232 and CurrentSize will be updated to the new size.
3234 If Source is NULL, there is nothing to append, just return the current buffer in
3237 if Destination is NULL, then ASSERT()
3238 if Destination's current length (including NULL terminator) is already more then
3239 CurrentSize, then ASSERT()
3241 @param[in, out] Destination The String to append onto
3242 @param[in, out] CurrentSize on call the number of bytes in Destination. On
3243 return possibly the new size (still in bytes). if NULL
3244 then allocate whatever is needed.
3245 @param[in] Source The String to append from
3246 @param[in] Count Maximum number of characters to append. if 0 then
3249 @return Destination return the resultant string.
3254 IN OUT CHAR16
**Destination
,
3255 IN OUT UINTN
*CurrentSize
,
3256 IN CONST CHAR16
*Source
,
3260 UINTN DestinationStartSize
;
3266 ASSERT(Destination
!= NULL
);
3269 // If there's nothing to do then just return Destination
3271 if (Source
== NULL
) {
3272 return (*Destination
);
3276 // allow for un-initialized pointers, based on size being 0
3278 if (CurrentSize
!= NULL
&& *CurrentSize
== 0) {
3279 *Destination
= NULL
;
3283 // allow for NULL pointers address as Destination
3285 if (*Destination
!= NULL
) {
3286 ASSERT(CurrentSize
!= 0);
3287 DestinationStartSize
= StrSize(*Destination
);
3288 ASSERT(DestinationStartSize
<= *CurrentSize
);
3290 DestinationStartSize
= 0;
3291 // ASSERT(*CurrentSize == 0);
3295 // Append all of Source?
3298 Count
= StrLen(Source
);
3302 // Test and grow if required
3304 if (CurrentSize
!= NULL
) {
3305 NewSize
= *CurrentSize
;
3306 if (NewSize
< DestinationStartSize
+ (Count
* sizeof(CHAR16
))) {
3307 while (NewSize
< (DestinationStartSize
+ (Count
*sizeof(CHAR16
)))) {
3308 NewSize
+= 2 * Count
* sizeof(CHAR16
);
3310 *Destination
= ReallocatePool(*CurrentSize
, NewSize
, *Destination
);
3311 *CurrentSize
= NewSize
;
3314 NewSize
= (Count
+1)*sizeof(CHAR16
);
3315 *Destination
= AllocateZeroPool(NewSize
);
3319 // Now use standard StrnCat on a big enough buffer
3321 if (*Destination
== NULL
) {
3325 StrnCatS(*Destination
, NewSize
/sizeof(CHAR16
), Source
, Count
);
3326 return *Destination
;
3330 Prompt the user and return the resultant answer to the requestor.
3332 This function will display the requested question on the shell prompt and then
3333 wait for an appropriate answer to be input from the console.
3335 if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
3336 or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
3338 if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
3341 In either case *Response must be callee freed if Response was not NULL;
3343 @param Type What type of question is asked. This is used to filter the input
3344 to prevent invalid answers to question.
3345 @param Prompt Pointer to string prompt to use to request input.
3346 @param Response Pointer to Response which will be populated upon return.
3348 @retval EFI_SUCCESS The operation was sucessful.
3349 @retval EFI_UNSUPPORTED The operation is not supported as requested.
3350 @retval EFI_INVALID_PARAMETER A parameter was invalid.
3351 @return other The operation failed.
3355 ShellPromptForResponse (
3356 IN SHELL_PROMPT_REQUEST_TYPE Type
,
3357 IN CHAR16
*Prompt OPTIONAL
,
3358 IN OUT VOID
**Response OPTIONAL
3364 SHELL_PROMPT_RESPONSE
*Resp
;
3368 Status
= EFI_UNSUPPORTED
;
3372 if (Type
!= ShellPromptResponseTypeFreeform
) {
3373 Resp
= (SHELL_PROMPT_RESPONSE
*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE
));
3375 return (EFI_OUT_OF_RESOURCES
);
3380 case ShellPromptResponseTypeQuitContinue
:
3381 if (Prompt
!= NULL
) {
3382 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3385 // wait for valid response
3387 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3388 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3389 if (EFI_ERROR(Status
)) {
3392 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3393 if (Key
.UnicodeChar
== L
'Q' || Key
.UnicodeChar
==L
'q') {
3394 *Resp
= ShellPromptResponseQuit
;
3396 *Resp
= ShellPromptResponseContinue
;
3399 case ShellPromptResponseTypeYesNoCancel
:
3400 if (Prompt
!= NULL
) {
3401 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3404 // wait for valid response
3406 *Resp
= ShellPromptResponseMax
;
3407 while (*Resp
== ShellPromptResponseMax
) {
3408 if (ShellGetExecutionBreakFlag()) {
3409 Status
= EFI_ABORTED
;
3412 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3413 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3414 if (EFI_ERROR(Status
)) {
3417 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3418 switch (Key
.UnicodeChar
) {
3421 *Resp
= ShellPromptResponseYes
;
3425 *Resp
= ShellPromptResponseNo
;
3429 *Resp
= ShellPromptResponseCancel
;
3434 case ShellPromptResponseTypeYesNoAllCancel
:
3435 if (Prompt
!= NULL
) {
3436 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3439 // wait for valid response
3441 *Resp
= ShellPromptResponseMax
;
3442 while (*Resp
== ShellPromptResponseMax
) {
3443 if (ShellGetExecutionBreakFlag()) {
3444 Status
= EFI_ABORTED
;
3447 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3448 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3449 if (EFI_ERROR(Status
)) {
3453 if (Key
.UnicodeChar
<= 127 && Key
.UnicodeChar
>= 32) {
3454 ShellPrintEx (-1, -1, L
"%c", Key
.UnicodeChar
);
3457 switch (Key
.UnicodeChar
) {
3460 *Resp
= ShellPromptResponseYes
;
3464 *Resp
= ShellPromptResponseNo
;
3468 *Resp
= ShellPromptResponseAll
;
3472 *Resp
= ShellPromptResponseCancel
;
3477 case ShellPromptResponseTypeEnterContinue
:
3478 case ShellPromptResponseTypeAnyKeyContinue
:
3479 if (Prompt
!= NULL
) {
3480 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3483 // wait for valid response
3485 *Resp
= ShellPromptResponseMax
;
3486 while (*Resp
== ShellPromptResponseMax
) {
3487 if (ShellGetExecutionBreakFlag()) {
3488 Status
= EFI_ABORTED
;
3491 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3492 if (Type
== ShellPromptResponseTypeEnterContinue
) {
3493 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3494 if (EFI_ERROR(Status
)) {
3497 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3498 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3499 *Resp
= ShellPromptResponseContinue
;
3503 if (Type
== ShellPromptResponseTypeAnyKeyContinue
) {
3504 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3505 ASSERT_EFI_ERROR(Status
);
3506 *Resp
= ShellPromptResponseContinue
;
3511 case ShellPromptResponseTypeYesNo
:
3512 if (Prompt
!= NULL
) {
3513 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3516 // wait for valid response
3518 *Resp
= ShellPromptResponseMax
;
3519 while (*Resp
== ShellPromptResponseMax
) {
3520 if (ShellGetExecutionBreakFlag()) {
3521 Status
= EFI_ABORTED
;
3524 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3525 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3526 if (EFI_ERROR(Status
)) {
3529 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3530 switch (Key
.UnicodeChar
) {
3533 *Resp
= ShellPromptResponseYes
;
3537 *Resp
= ShellPromptResponseNo
;
3542 case ShellPromptResponseTypeFreeform
:
3543 if (Prompt
!= NULL
) {
3544 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3547 if (ShellGetExecutionBreakFlag()) {
3548 Status
= EFI_ABORTED
;
3551 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3552 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3553 if (EFI_ERROR(Status
)) {
3556 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3557 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3560 ASSERT((Buffer
== NULL
&& Size
== 0) || (Buffer
!= NULL
));
3561 StrnCatGrow(&Buffer
, &Size
, &Key
.UnicodeChar
, 1);
3565 // This is the location to add new prompt types.
3566 // If your new type loops remember to add ExecutionBreak support.
3572 if (Response
!= NULL
) {
3575 } else if (Buffer
!= NULL
) {
3582 if (Buffer
!= NULL
) {
3587 ShellPrintEx(-1, -1, L
"\r\n");
3592 Prompt the user and return the resultant answer to the requestor.
3594 This function is the same as ShellPromptForResponse, except that the prompt is
3595 automatically pulled from HII.
3597 @param Type What type of question is asked. This is used to filter the input
3598 to prevent invalid answers to question.
3599 @param[in] HiiFormatStringId The format string Id for getting from Hii.
3600 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
3601 @param Response Pointer to Response which will be populated upon return.
3603 @retval EFI_SUCCESS the operation was sucessful.
3604 @return other the operation failed.
3606 @sa ShellPromptForResponse
3610 ShellPromptForResponseHii (
3611 IN SHELL_PROMPT_REQUEST_TYPE Type
,
3612 IN CONST EFI_STRING_ID HiiFormatStringId
,
3613 IN CONST EFI_HANDLE HiiFormatHandle
,
3614 IN OUT VOID
**Response
3620 Prompt
= HiiGetString(HiiFormatHandle
, HiiFormatStringId
, NULL
);
3621 Status
= ShellPromptForResponse(Type
, Prompt
, Response
);
3627 Function to determin if an entire string is a valid number.
3629 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
3631 @param[in] String The string to evaluate.
3632 @param[in] ForceHex TRUE - always assume hex.
3633 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
3634 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
3636 @retval TRUE It is all numeric (dec/hex) characters.
3637 @retval FALSE There is a non-numeric character.
3640 InternalShellIsHexOrDecimalNumber (
3641 IN CONST CHAR16
*String
,
3642 IN CONST BOOLEAN ForceHex
,
3643 IN CONST BOOLEAN StopAtSpace
,
3644 IN CONST BOOLEAN TimeNumbers
3648 BOOLEAN LeadingZero
;
3650 if (String
== NULL
) {
3655 // chop off a single negative sign
3657 if (*String
== L
'-') {
3661 if (*String
== CHAR_NULL
) {
3666 // chop leading zeroes
3668 LeadingZero
= FALSE
;
3669 while(*String
== L
'0'){
3674 // allow '0x' or '0X', but not 'x' or 'X'
3676 if (*String
== L
'x' || *String
== L
'X') {
3679 // we got an x without a preceeding 0
3685 } else if (ForceHex
) {
3692 // loop through the remaining characters and use the lib function
3694 for ( ; *String
!= CHAR_NULL
&& !(StopAtSpace
&& *String
== L
' ') ; String
++){
3695 if (TimeNumbers
&& (String
[0] == L
':')) {
3699 if (!ShellIsHexaDecimalDigitCharacter(*String
)) {
3703 if (!ShellIsDecimalDigitCharacter(*String
)) {
3713 Function to determine if a given filename exists.
3715 @param[in] Name Path to test.
3717 @retval EFI_SUCCESS The Path represents a file.
3718 @retval EFI_NOT_FOUND The Path does not represent a file.
3719 @retval other The path failed to open.
3724 IN CONST CHAR16
*Name
3728 EFI_SHELL_FILE_INFO
*List
;
3730 ASSERT(Name
!= NULL
);
3733 Status
= ShellOpenFileMetaArg((CHAR16
*)Name
, EFI_FILE_MODE_READ
, &List
);
3734 if (EFI_ERROR(Status
)) {
3738 ShellCloseFileMetaArg(&List
);
3740 return (EFI_SUCCESS
);
3744 Convert a Unicode character to upper case only if
3745 it maps to a valid small-case ASCII character.
3747 This internal function only deal with Unicode character
3748 which maps to a valid small-case ASCII character, i.e.
3749 L'a' to L'z'. For other Unicode character, the input character
3750 is returned directly.
3752 @param Char The character to convert.
3754 @retval LowerCharacter If the Char is with range L'a' to L'z'.
3755 @retval Unchanged Otherwise.
3759 InternalShellCharToUpper (
3763 if (Char
>= L
'a' && Char
<= L
'z') {
3764 return (CHAR16
) (Char
- (L
'a' - L
'A'));
3771 Convert a Unicode character to numerical value.
3773 This internal function only deal with Unicode character
3774 which maps to a valid hexadecimal ASII character, i.e.
3775 L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
3776 Unicode character, the value returned does not make sense.
3778 @param Char The character to convert.
3780 @return The numerical value converted.
3784 InternalShellHexCharToUintn (
3788 if (ShellIsDecimalDigitCharacter (Char
)) {
3792 return (10 + InternalShellCharToUpper (Char
) - L
'A');
3796 Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
3798 This function returns a value of type UINT64 by interpreting the contents
3799 of the Unicode string specified by String as a hexadecimal number.
3800 The format of the input Unicode string String is:
3802 [spaces][zeros][x][hexadecimal digits].
3804 The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
3805 The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
3806 If "x" appears in the input string, it must be prefixed with at least one 0.
3807 The function will ignore the pad space, which includes spaces or tab characters,
3808 before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
3809 [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
3810 first valid hexadecimal digit. Then, the function stops at the first character that is
3811 a not a valid hexadecimal character or NULL, whichever one comes first.
3813 If String has only pad spaces, then zero is returned.
3814 If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
3815 then zero is returned.
3817 @param[in] String A pointer to a Null-terminated Unicode string.
3818 @param[out] Value Upon a successful return the value of the conversion.
3819 @param[in] StopAtSpace FALSE to skip spaces.
3821 @retval EFI_SUCCESS The conversion was successful.
3822 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3823 @retval EFI_DEVICE_ERROR An overflow occured.
3826 InternalShellStrHexToUint64 (
3827 IN CONST CHAR16
*String
,
3829 IN CONST BOOLEAN StopAtSpace
3834 if (String
== NULL
|| StrSize(String
) == 0 || Value
== NULL
) {
3835 return (EFI_INVALID_PARAMETER
);
3839 // Ignore the pad spaces (space or tab)
3841 while ((*String
== L
' ') || (*String
== L
'\t')) {
3846 // Ignore leading Zeros after the spaces
3848 while (*String
== L
'0') {
3852 if (InternalShellCharToUpper (*String
) == L
'X') {
3853 if (*(String
- 1) != L
'0') {
3865 // there is a space where there should't be
3867 if (*String
== L
' ') {
3868 return (EFI_INVALID_PARAMETER
);
3871 while (ShellIsHexaDecimalDigitCharacter (*String
)) {
3873 // If the Hex Number represented by String overflows according
3874 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3876 if (!(Result
<= (RShiftU64((((UINT64
) ~0) - InternalShellHexCharToUintn (*String
)), 4)))) {
3877 // if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
3878 return (EFI_DEVICE_ERROR
);
3881 Result
= (LShiftU64(Result
, 4));
3882 Result
+= InternalShellHexCharToUintn (*String
);
3886 // stop at spaces if requested
3888 if (StopAtSpace
&& *String
== L
' ') {
3894 return (EFI_SUCCESS
);
3898 Convert a Null-terminated Unicode decimal string to a value of
3901 This function returns a value of type UINT64 by interpreting the contents
3902 of the Unicode string specified by String as a decimal number. The format
3903 of the input Unicode string String is:
3905 [spaces] [decimal digits].
3907 The valid decimal digit character is in the range [0-9]. The
3908 function will ignore the pad space, which includes spaces or
3909 tab characters, before [decimal digits]. The running zero in the
3910 beginning of [decimal digits] will be ignored. Then, the function
3911 stops at the first character that is a not a valid decimal character
3912 or a Null-terminator, whichever one comes first.
3914 If String has only pad spaces, then 0 is returned.
3915 If String has no pad spaces or valid decimal digits,
3918 @param[in] String A pointer to a Null-terminated Unicode string.
3919 @param[out] Value Upon a successful return the value of the conversion.
3920 @param[in] StopAtSpace FALSE to skip spaces.
3922 @retval EFI_SUCCESS The conversion was successful.
3923 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3924 @retval EFI_DEVICE_ERROR An overflow occured.
3927 InternalShellStrDecimalToUint64 (
3928 IN CONST CHAR16
*String
,
3930 IN CONST BOOLEAN StopAtSpace
3935 if (String
== NULL
|| StrSize (String
) == 0 || Value
== NULL
) {
3936 return (EFI_INVALID_PARAMETER
);
3940 // Ignore the pad spaces (space or tab)
3942 while ((*String
== L
' ') || (*String
== L
'\t')) {
3947 // Ignore leading Zeros after the spaces
3949 while (*String
== L
'0') {
3956 // Stop upon space if requested
3957 // (if the whole value was 0)
3959 if (StopAtSpace
&& *String
== L
' ') {
3961 return (EFI_SUCCESS
);
3964 while (ShellIsDecimalDigitCharacter (*String
)) {
3966 // If the number represented by String overflows according
3967 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3970 if (!(Result
<= (DivU64x32((((UINT64
) ~0) - (*String
- L
'0')),10)))) {
3971 return (EFI_DEVICE_ERROR
);
3974 Result
= MultU64x32(Result
, 10) + (*String
- L
'0');
3978 // Stop at spaces if requested
3980 if (StopAtSpace
&& *String
== L
' ') {
3987 return (EFI_SUCCESS
);
3991 Function to verify and convert a string to its numerical value.
3993 If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
3995 @param[in] String The string to evaluate.
3996 @param[out] Value Upon a successful return the value of the conversion.
3997 @param[in] ForceHex TRUE - always assume hex.
3998 @param[in] StopAtSpace FALSE to skip spaces.
4000 @retval EFI_SUCCESS The conversion was successful.
4001 @retval EFI_INVALID_PARAMETER String contained an invalid character.
4002 @retval EFI_NOT_FOUND String was a number, but Value was NULL.
4006 ShellConvertStringToUint64(
4007 IN CONST CHAR16
*String
,
4009 IN CONST BOOLEAN ForceHex
,
4010 IN CONST BOOLEAN StopAtSpace
4014 CONST CHAR16
*Walker
;
4020 if (!InternalShellIsHexOrDecimalNumber(String
, Hex
, StopAtSpace
, FALSE
)) {
4023 if (!InternalShellIsHexOrDecimalNumber(String
, Hex
, StopAtSpace
, FALSE
)) {
4024 return (EFI_INVALID_PARAMETER
);
4027 return (EFI_INVALID_PARAMETER
);
4032 // Chop off leading spaces
4034 for (Walker
= String
; Walker
!= NULL
&& *Walker
!= CHAR_NULL
&& *Walker
== L
' '; Walker
++);
4037 // make sure we have something left that is numeric.
4039 if (Walker
== NULL
|| *Walker
== CHAR_NULL
|| !InternalShellIsHexOrDecimalNumber(Walker
, Hex
, StopAtSpace
, FALSE
)) {
4040 return (EFI_INVALID_PARAMETER
);
4044 // do the conversion.
4046 if (Hex
|| StrnCmp(Walker
, L
"0x", 2) == 0 || StrnCmp(Walker
, L
"0X", 2) == 0){
4047 Status
= InternalShellStrHexToUint64(Walker
, &RetVal
, StopAtSpace
);
4049 Status
= InternalShellStrDecimalToUint64(Walker
, &RetVal
, StopAtSpace
);
4052 if (Value
== NULL
&& !EFI_ERROR(Status
)) {
4053 return (EFI_NOT_FOUND
);
4056 if (Value
!= NULL
) {
4064 Function to determin if an entire string is a valid number.
4066 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
4068 @param[in] String The string to evaluate.
4069 @param[in] ForceHex TRUE - always assume hex.
4070 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
4072 @retval TRUE It is all numeric (dec/hex) characters.
4073 @retval FALSE There is a non-numeric character.
4077 ShellIsHexOrDecimalNumber (
4078 IN CONST CHAR16
*String
,
4079 IN CONST BOOLEAN ForceHex
,
4080 IN CONST BOOLEAN StopAtSpace
4083 if (ShellConvertStringToUint64(String
, NULL
, ForceHex
, StopAtSpace
) == EFI_NOT_FOUND
) {
4090 Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
4091 buffer. The returned buffer must be callee freed.
4093 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4094 maintained and not changed for all operations with the same file.
4096 @param[in] Handle SHELL_FILE_HANDLE to read from.
4097 @param[in, out] Ascii Boolean value for indicating whether the file is
4098 Ascii (TRUE) or UCS2 (FALSE).
4100 @return The line of text from the file.
4101 @retval NULL There was not enough memory available.
4103 @sa ShellFileHandleReadLine
4107 ShellFileHandleReturnLine(
4108 IN SHELL_FILE_HANDLE Handle
,
4109 IN OUT BOOLEAN
*Ascii
4119 Status
= ShellFileHandleReadLine(Handle
, RetVal
, &Size
, FALSE
, Ascii
);
4120 if (Status
== EFI_BUFFER_TOO_SMALL
) {
4121 RetVal
= AllocateZeroPool(Size
);
4122 if (RetVal
== NULL
) {
4125 Status
= ShellFileHandleReadLine(Handle
, RetVal
, &Size
, FALSE
, Ascii
);
4128 if (Status
== EFI_END_OF_FILE
&& RetVal
!= NULL
&& *RetVal
!= CHAR_NULL
) {
4129 Status
= EFI_SUCCESS
;
4131 if (EFI_ERROR(Status
) && (RetVal
!= NULL
)) {
4139 Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
4141 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4142 maintained and not changed for all operations with the same file.
4144 NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ
4147 @param[in] Handle SHELL_FILE_HANDLE to read from.
4148 @param[in, out] Buffer The pointer to buffer to read into. If this function
4149 returns EFI_SUCCESS, then on output Buffer will
4150 contain a UCS2 string, even if the file being
4152 @param[in, out] Size On input, pointer to number of bytes in Buffer.
4153 On output, unchanged unless Buffer is too small
4154 to contain the next line of the file. In that
4155 case Size is set to the number of bytes needed
4156 to hold the next line of the file (as a UCS2
4157 string, even if it is an ASCII file).
4158 @param[in] Truncate If the buffer is large enough, this has no effect.
4159 If the buffer is is too small and Truncate is TRUE,
4160 the line will be truncated.
4161 If the buffer is is too small and Truncate is FALSE,
4162 then no read will occur.
4164 @param[in, out] Ascii Boolean value for indicating whether the file is
4165 Ascii (TRUE) or UCS2 (FALSE).
4167 @retval EFI_SUCCESS The operation was successful. The line is stored in
4169 @retval EFI_END_OF_FILE There are no more lines in the file.
4170 @retval EFI_INVALID_PARAMETER Handle was NULL.
4171 @retval EFI_INVALID_PARAMETER Size was NULL.
4172 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
4173 Size was updated to the minimum space required.
4177 ShellFileHandleReadLine(
4178 IN SHELL_FILE_HANDLE Handle
,
4179 IN OUT CHAR16
*Buffer
,
4181 IN BOOLEAN Truncate
,
4182 IN OUT BOOLEAN
*Ascii
4189 UINT64 OriginalFilePosition
;
4195 return (EFI_INVALID_PARAMETER
);
4197 if (Buffer
== NULL
) {
4200 *Buffer
= CHAR_NULL
;
4202 gEfiShellProtocol
->GetFilePosition(Handle
, &OriginalFilePosition
);
4203 if (OriginalFilePosition
== 0) {
4204 CharSize
= sizeof(CHAR16
);
4205 Status
= gEfiShellProtocol
->ReadFile(Handle
, &CharSize
, &CharBuffer
);
4206 ASSERT_EFI_ERROR(Status
);
4207 if (CharBuffer
== gUnicodeFileTag
) {
4211 gEfiShellProtocol
->SetFilePosition(Handle
, OriginalFilePosition
);
4216 CharSize
= sizeof(CHAR8
);
4218 CharSize
= sizeof(CHAR16
);
4220 for (CountSoFar
= 0;;CountSoFar
++){
4222 Status
= gEfiShellProtocol
->ReadFile(Handle
, &CharSize
, &CharBuffer
);
4223 if ( EFI_ERROR(Status
)
4225 || (CharBuffer
== L
'\n' && !(*Ascii
))
4226 || (CharBuffer
== '\n' && *Ascii
)
4228 if (CharSize
== 0) {
4229 Status
= EFI_END_OF_FILE
;
4234 // if we have space save it...
4236 if ((CountSoFar
+1)*sizeof(CHAR16
) < *Size
){
4237 ASSERT(Buffer
!= NULL
);
4238 ((CHAR16
*)Buffer
)[CountSoFar
] = CharBuffer
;
4239 ((CHAR16
*)Buffer
)[CountSoFar
+1] = CHAR_NULL
;
4244 // if we ran out of space tell when...
4246 if ((CountSoFar
+1)*sizeof(CHAR16
) > *Size
){
4247 *Size
= (CountSoFar
+1)*sizeof(CHAR16
);
4249 gEfiShellProtocol
->SetFilePosition(Handle
, OriginalFilePosition
);
4251 DEBUG((DEBUG_WARN
, "The line was truncated in ShellFileHandleReadLine"));
4253 return (EFI_BUFFER_TOO_SMALL
);
4255 while(Buffer
[StrLen(Buffer
)-1] == L
'\r') {
4256 Buffer
[StrLen(Buffer
)-1] = CHAR_NULL
;
4263 Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
4265 @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
4266 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
4267 @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
4268 the help content only.
4269 @retval EFI_DEVICE_ERROR The help data format was incorrect.
4270 @retval EFI_NOT_FOUND The help data could not be found.
4271 @retval EFI_SUCCESS The operation was successful.
4276 IN CONST CHAR16
*CommandToGetHelpOn
,
4277 IN CONST CHAR16
*SectionToGetHelpOn
,
4278 IN BOOLEAN PrintCommandText
4287 // Get the string to print based
4289 Status
= gEfiShellProtocol
->GetHelpText (CommandToGetHelpOn
, SectionToGetHelpOn
, &OutText
);
4292 // make sure we got a valid string
4294 if (EFI_ERROR(Status
)){
4297 if (OutText
== NULL
|| StrLen(OutText
) == 0) {
4298 return EFI_NOT_FOUND
;
4302 // Chop off trailing stuff we dont need
4304 while (OutText
[StrLen(OutText
)-1] == L
'\r' || OutText
[StrLen(OutText
)-1] == L
'\n' || OutText
[StrLen(OutText
)-1] == L
' ') {
4305 OutText
[StrLen(OutText
)-1] = CHAR_NULL
;
4309 // Print this out to the console
4311 if (PrintCommandText
) {
4312 ShellPrintEx(-1, -1, L
"%H%-14s%N- %s\r\n", CommandToGetHelpOn
, OutText
);
4314 ShellPrintEx(-1, -1, L
"%N%s\r\n", OutText
);
4317 SHELL_FREE_NON_NULL(OutText
);
4323 Function to delete a file by name
4325 @param[in] FileName Pointer to file name to delete.
4327 @retval EFI_SUCCESS the file was deleted sucessfully
4328 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
4330 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
4331 @retval EFI_NOT_FOUND The specified file could not be found on the
4332 device or the file system could not be found
4334 @retval EFI_NO_MEDIA The device has no medium.
4335 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
4336 medium is no longer supported.
4337 @retval EFI_DEVICE_ERROR The device reported an error.
4338 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
4339 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
4340 @retval EFI_ACCESS_DENIED The file was opened read only.
4341 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
4343 @retval other The file failed to open
4347 ShellDeleteFileByName(
4348 IN CONST CHAR16
*FileName
4352 SHELL_FILE_HANDLE FileHandle
;
4354 Status
= ShellFileExists(FileName
);
4356 if (Status
== EFI_SUCCESS
){
4357 Status
= ShellOpenFileByName(FileName
, &FileHandle
, EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0x0);
4358 if (Status
== EFI_SUCCESS
){
4359 Status
= ShellDeleteFile(&FileHandle
);
4368 Cleans off all the quotes in the string.
4370 @param[in] OriginalString pointer to the string to be cleaned.
4371 @param[out] CleanString The new string with all quotes removed.
4372 Memory allocated in the function and free
4375 @retval EFI_SUCCESS The operation was successful.
4378 InternalShellStripQuotes (
4379 IN CONST CHAR16
*OriginalString
,
4380 OUT CHAR16
**CleanString
4385 if (OriginalString
== NULL
|| CleanString
== NULL
) {
4386 return EFI_INVALID_PARAMETER
;
4389 *CleanString
= AllocateCopyPool (StrSize (OriginalString
), OriginalString
);
4390 if (*CleanString
== NULL
) {
4391 return EFI_OUT_OF_RESOURCES
;
4394 for (Walker
= *CleanString
; Walker
!= NULL
&& *Walker
!= CHAR_NULL
; Walker
++) {
4395 if (*Walker
== L
'\"') {
4396 CopyMem(Walker
, Walker
+1, StrSize(Walker
) - sizeof(Walker
[0]));