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 - 2019, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include "UefiShellLib.h"
12 #include <Library/SortLib.h>
13 #include <Library/BaseLib.h>
18 SHELL_PARAM_ITEM EmptyParamList
[] = {
21 SHELL_PARAM_ITEM SfoParamList
[] = {
25 EFI_SHELL_ENVIRONMENT2
*mEfiShellEnvironment2
;
26 EFI_SHELL_INTERFACE
*mEfiShellInterface
;
27 EFI_SHELL_PROTOCOL
*gEfiShellProtocol
;
28 EFI_SHELL_PARAMETERS_PROTOCOL
*gEfiShellParametersProtocol
;
29 EFI_HANDLE mEfiShellEnvironment2Handle
;
30 FILE_HANDLE_FUNCTION_MAP FileFunctionMap
;
31 EFI_UNICODE_COLLATION_PROTOCOL
*mUnicodeCollationProtocol
;
34 Return a clean, fully-qualified version of an input path. If the return value
35 is non-NULL the caller must free the memory when it is no longer needed.
37 If asserts are disabled, and if the input parameter is NULL, NULL is returned.
39 If there is not enough memory available to create the fully-qualified path or
40 a copy of the input path, NULL is returned.
42 If there is no working directory, a clean copy of Path is returned.
44 Otherwise, the current file system or working directory (as appropriate) is
45 prepended to Path and the resulting path is cleaned and returned.
47 NOTE: If the input path is an empty string, then the current working directory
48 (if it exists) is returned. In other words, an empty input path is treated
49 exactly the same as ".".
51 @param[in] Path A pointer to some file or directory path.
53 @retval NULL The input path is NULL or out of memory.
55 @retval non-NULL A pointer to a clean, fully-qualified version of Path.
56 If there is no working directory, then a pointer to a
57 clean, but not necessarily fully-qualified version of
58 Path. The caller must free this memory when it is no
67 CONST CHAR16
*WorkingPath
;
68 CONST CHAR16
*InputPath
;
70 CHAR16
*InputFileSystem
;
71 UINTN FileSystemCharCount
;
72 CHAR16
*FullyQualifiedPath
;
75 FullyQualifiedPath
= NULL
;
79 // Handle erroneous input when asserts are disabled.
85 // In paths that contain ":", like fs0:dir/file.ext and fs2:\fqpath\file.ext,
86 // we have to consider the file system part separately from the "path" part.
87 // If there is a file system in the path, we have to get the current working
88 // directory for that file system. Then we need to use the part of the path
89 // following the ":". If a path does not contain ":", we use it as given.
91 InputPath
= StrStr(Path
, L
":");
92 if (InputPath
!= NULL
) {
94 FileSystemCharCount
= ((UINTN
)InputPath
- (UINTN
)Path
+ sizeof(CHAR16
)) / sizeof(CHAR16
);
95 InputFileSystem
= AllocateCopyPool(FileSystemCharCount
* sizeof(CHAR16
), Path
);
96 if (InputFileSystem
!= NULL
) {
97 InputFileSystem
[FileSystemCharCount
- 1] = CHAR_NULL
;
99 WorkingPath
= ShellGetCurrentDir(InputFileSystem
);
100 SHELL_FREE_NON_NULL(InputFileSystem
);
103 WorkingPath
= ShellGetEnvironmentVariable(L
"cwd");
106 if (WorkingPath
== NULL
) {
108 // With no working directory, all we can do is copy and clean the input path.
110 FullyQualifiedPath
= AllocateCopyPool(StrSize(Path
), Path
);
113 // Allocate space for both strings plus one more character.
115 Size
= StrSize(WorkingPath
) + StrSize(InputPath
);
116 FullyQualifiedPath
= AllocateZeroPool(Size
);
117 if (FullyQualifiedPath
== NULL
) {
119 // Try to copy and clean just the input. No harm if not enough memory.
121 FullyQualifiedPath
= AllocateCopyPool(StrSize(Path
), Path
);
123 if (*InputPath
== L
'\\' || *InputPath
== L
'/') {
125 // Absolute path: start with the current working directory, then
126 // truncate the new path after the file system part.
128 StrCpyS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), WorkingPath
);
129 CharPtr
= StrStr(FullyQualifiedPath
, L
":");
130 if (CharPtr
!= NULL
) {
131 *(CharPtr
+ 1) = CHAR_NULL
;
135 // Relative path: start with the working directory and append "\".
137 StrCpyS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), WorkingPath
);
138 StrCatS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), L
"\\");
141 // Now append the absolute or relative path.
143 StrCatS(FullyQualifiedPath
, Size
/sizeof(CHAR16
), InputPath
);
147 PathCleanUpDirectories(FullyQualifiedPath
);
149 return FullyQualifiedPath
;
153 Check if a Unicode character is a hexadecimal character.
155 This internal function checks if a Unicode character is a
156 numeric character. The valid hexadecimal characters are
157 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
159 @param Char The character to check against.
161 @retval TRUE If the Char is a hexadecmial character.
162 @retval FALSE If the Char is not a hexadecmial character.
167 ShellIsHexaDecimalDigitCharacter (
171 return (BOOLEAN
) ((Char
>= L
'0' && Char
<= L
'9') || (Char
>= L
'A' && Char
<= L
'F') || (Char
>= L
'a' && Char
<= L
'f'));
175 Check if a Unicode character is a decimal character.
177 This internal function checks if a Unicode character is a
178 decimal character. The valid characters are
182 @param Char The character to check against.
184 @retval TRUE If the Char is a hexadecmial character.
185 @retval FALSE If the Char is not a hexadecmial character.
190 ShellIsDecimalDigitCharacter (
194 return (BOOLEAN
) (Char
>= L
'0' && Char
<= L
'9');
198 Helper function to find ShellEnvironment2 for constructor.
200 @param[in] ImageHandle A copy of the calling image's handle.
202 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
206 IN EFI_HANDLE ImageHandle
216 Status
= gBS
->OpenProtocol(ImageHandle
,
217 &gEfiShellEnvironment2Guid
,
218 (VOID
**)&mEfiShellEnvironment2
,
221 EFI_OPEN_PROTOCOL_GET_PROTOCOL
224 // look for the mEfiShellEnvironment2 protocol at a higher level
226 if (EFI_ERROR (Status
) || !(CompareGuid (&mEfiShellEnvironment2
->SESGuid
, &gEfiShellEnvironment2ExtGuid
))){
228 // figure out how big of a buffer we need.
230 Status
= gBS
->LocateHandle (ByProtocol
,
231 &gEfiShellEnvironment2Guid
,
232 NULL
, // ignored for ByProtocol
237 // maybe it's not there???
239 if (Status
== EFI_BUFFER_TOO_SMALL
) {
240 Buffer
= (EFI_HANDLE
*)AllocateZeroPool(BufferSize
);
241 if (Buffer
== NULL
) {
242 return (EFI_OUT_OF_RESOURCES
);
244 Status
= gBS
->LocateHandle (ByProtocol
,
245 &gEfiShellEnvironment2Guid
,
246 NULL
, // ignored for ByProtocol
251 if (!EFI_ERROR (Status
) && Buffer
!= NULL
) {
253 // now parse the list of returned handles
255 Status
= EFI_NOT_FOUND
;
256 for (HandleIndex
= 0; HandleIndex
< (BufferSize
/sizeof(Buffer
[0])); HandleIndex
++) {
257 Status
= gBS
->OpenProtocol(Buffer
[HandleIndex
],
258 &gEfiShellEnvironment2Guid
,
259 (VOID
**)&mEfiShellEnvironment2
,
262 EFI_OPEN_PROTOCOL_GET_PROTOCOL
264 if (CompareGuid (&mEfiShellEnvironment2
->SESGuid
, &gEfiShellEnvironment2ExtGuid
)) {
265 mEfiShellEnvironment2Handle
= Buffer
[HandleIndex
];
266 Status
= EFI_SUCCESS
;
272 if (Buffer
!= NULL
) {
279 Function to do most of the work of the constructor. Allows for calling
280 multiple times without complete re-initialization.
282 @param[in] ImageHandle A copy of the ImageHandle.
283 @param[in] SystemTable A pointer to the SystemTable for the application.
285 @retval EFI_SUCCESS The operationw as successful.
288 ShellLibConstructorWorker (
289 IN EFI_HANDLE ImageHandle
,
290 IN EFI_SYSTEM_TABLE
*SystemTable
295 if (gEfiShellProtocol
== NULL
) {
297 // UEFI 2.0 shell interfaces (used preferentially)
299 Status
= gBS
->OpenProtocol (
301 &gEfiShellProtocolGuid
,
302 (VOID
**)&gEfiShellProtocol
,
305 EFI_OPEN_PROTOCOL_GET_PROTOCOL
307 if (EFI_ERROR (Status
)) {
309 // Search for the shell protocol
311 Status
= gBS
->LocateProtocol (
312 &gEfiShellProtocolGuid
,
314 (VOID
**)&gEfiShellProtocol
316 if (EFI_ERROR (Status
)) {
317 gEfiShellProtocol
= NULL
;
322 if (gEfiShellParametersProtocol
== NULL
) {
323 Status
= gBS
->OpenProtocol (
325 &gEfiShellParametersProtocolGuid
,
326 (VOID
**)&gEfiShellParametersProtocol
,
329 EFI_OPEN_PROTOCOL_GET_PROTOCOL
331 if (EFI_ERROR (Status
)) {
332 gEfiShellParametersProtocol
= NULL
;
336 if (gEfiShellProtocol
== NULL
) {
338 // Moved to seperate function due to complexity
340 Status
= ShellFindSE2(ImageHandle
);
342 if (EFI_ERROR(Status
)) {
343 DEBUG((DEBUG_ERROR
, "Status: 0x%08x\r\n", Status
));
344 mEfiShellEnvironment2
= NULL
;
346 Status
= gBS
->OpenProtocol(ImageHandle
,
347 &gEfiShellInterfaceGuid
,
348 (VOID
**)&mEfiShellInterface
,
351 EFI_OPEN_PROTOCOL_GET_PROTOCOL
353 if (EFI_ERROR(Status
)) {
354 mEfiShellInterface
= NULL
;
359 // Getting either EDK Shell's ShellEnvironment2 and ShellInterface protocol
360 // or UEFI Shell's Shell protocol.
361 // When ShellLib is linked to a driver producing DynamicCommand protocol,
362 // ShellParameters protocol is set by DynamicCommand.Handler().
364 if ((mEfiShellEnvironment2
!= NULL
&& mEfiShellInterface
!= NULL
) ||
365 (gEfiShellProtocol
!= NULL
)
367 if (gEfiShellProtocol
!= NULL
) {
368 FileFunctionMap
.GetFileInfo
= gEfiShellProtocol
->GetFileInfo
;
369 FileFunctionMap
.SetFileInfo
= gEfiShellProtocol
->SetFileInfo
;
370 FileFunctionMap
.ReadFile
= gEfiShellProtocol
->ReadFile
;
371 FileFunctionMap
.WriteFile
= gEfiShellProtocol
->WriteFile
;
372 FileFunctionMap
.CloseFile
= gEfiShellProtocol
->CloseFile
;
373 FileFunctionMap
.DeleteFile
= gEfiShellProtocol
->DeleteFile
;
374 FileFunctionMap
.GetFilePosition
= gEfiShellProtocol
->GetFilePosition
;
375 FileFunctionMap
.SetFilePosition
= gEfiShellProtocol
->SetFilePosition
;
376 FileFunctionMap
.FlushFile
= gEfiShellProtocol
->FlushFile
;
377 FileFunctionMap
.GetFileSize
= gEfiShellProtocol
->GetFileSize
;
379 FileFunctionMap
.GetFileInfo
= (EFI_SHELL_GET_FILE_INFO
)FileHandleGetInfo
;
380 FileFunctionMap
.SetFileInfo
= (EFI_SHELL_SET_FILE_INFO
)FileHandleSetInfo
;
381 FileFunctionMap
.ReadFile
= (EFI_SHELL_READ_FILE
)FileHandleRead
;
382 FileFunctionMap
.WriteFile
= (EFI_SHELL_WRITE_FILE
)FileHandleWrite
;
383 FileFunctionMap
.CloseFile
= (EFI_SHELL_CLOSE_FILE
)FileHandleClose
;
384 FileFunctionMap
.DeleteFile
= (EFI_SHELL_DELETE_FILE
)FileHandleDelete
;
385 FileFunctionMap
.GetFilePosition
= (EFI_SHELL_GET_FILE_POSITION
)FileHandleGetPosition
;
386 FileFunctionMap
.SetFilePosition
= (EFI_SHELL_SET_FILE_POSITION
)FileHandleSetPosition
;
387 FileFunctionMap
.FlushFile
= (EFI_SHELL_FLUSH_FILE
)FileHandleFlush
;
388 FileFunctionMap
.GetFileSize
= (EFI_SHELL_GET_FILE_SIZE
)FileHandleGetSize
;
390 return (EFI_SUCCESS
);
392 return (EFI_NOT_FOUND
);
395 Constructor for the Shell library.
397 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
399 @param ImageHandle the image handle of the process
400 @param SystemTable the EFI System Table pointer
402 @retval EFI_SUCCESS the initialization was complete sucessfully
403 @return others an error ocurred during initialization
407 ShellLibConstructor (
408 IN EFI_HANDLE ImageHandle
,
409 IN EFI_SYSTEM_TABLE
*SystemTable
412 mEfiShellEnvironment2
= NULL
;
413 gEfiShellProtocol
= NULL
;
414 gEfiShellParametersProtocol
= NULL
;
415 mEfiShellInterface
= NULL
;
416 mEfiShellEnvironment2Handle
= NULL
;
417 mUnicodeCollationProtocol
= NULL
;
420 // verify that auto initialize is not set false
422 if (PcdGetBool(PcdShellLibAutoInitialize
) == 0) {
423 return (EFI_SUCCESS
);
426 return (ShellLibConstructorWorker(ImageHandle
, SystemTable
));
430 Destructor for the library. free any resources.
432 @param[in] ImageHandle A copy of the ImageHandle.
433 @param[in] SystemTable A pointer to the SystemTable for the application.
435 @retval EFI_SUCCESS The operation was successful.
436 @return An error from the CloseProtocol function.
441 IN EFI_HANDLE ImageHandle
,
442 IN EFI_SYSTEM_TABLE
*SystemTable
447 if (mEfiShellEnvironment2
!= NULL
) {
448 Status
= gBS
->CloseProtocol(mEfiShellEnvironment2Handle
==NULL
?ImageHandle
:mEfiShellEnvironment2Handle
,
449 &gEfiShellEnvironment2Guid
,
452 if (!EFI_ERROR (Status
)) {
453 mEfiShellEnvironment2
= NULL
;
454 mEfiShellEnvironment2Handle
= NULL
;
457 if (mEfiShellInterface
!= NULL
) {
458 Status
= gBS
->CloseProtocol(ImageHandle
,
459 &gEfiShellInterfaceGuid
,
462 if (!EFI_ERROR (Status
)) {
463 mEfiShellInterface
= NULL
;
466 if (gEfiShellProtocol
!= NULL
) {
467 Status
= gBS
->CloseProtocol(ImageHandle
,
468 &gEfiShellProtocolGuid
,
471 if (!EFI_ERROR (Status
)) {
472 gEfiShellProtocol
= NULL
;
475 if (gEfiShellParametersProtocol
!= NULL
) {
476 Status
= gBS
->CloseProtocol(ImageHandle
,
477 &gEfiShellParametersProtocolGuid
,
480 if (!EFI_ERROR (Status
)) {
481 gEfiShellParametersProtocol
= NULL
;
485 return (EFI_SUCCESS
);
489 This function causes the shell library to initialize itself. If the shell library
490 is already initialized it will de-initialize all the current protocol poitners and
491 re-populate them again.
493 When the library is used with PcdShellLibAutoInitialize set to true this function
494 will return EFI_SUCCESS and perform no actions.
496 This function is intended for internal access for shell commands only.
498 @retval EFI_SUCCESS the initialization was complete sucessfully
510 // if auto initialize is not false then skip
512 if (PcdGetBool(PcdShellLibAutoInitialize
) != 0) {
513 return (EFI_SUCCESS
);
517 // deinit the current stuff
519 Status
= ShellLibDestructor (gImageHandle
, gST
);
520 ASSERT_EFI_ERROR (Status
);
523 // init the new stuff
525 return (ShellLibConstructorWorker(gImageHandle
, gST
));
529 This function will retrieve the information about the file for the handle
530 specified and store it in allocated pool memory.
532 This function allocates a buffer to store the file's information. It is the
533 caller's responsibility to free the buffer
535 @param FileHandle The file handle of the file for which information is
538 @retval NULL information could not be retrieved.
540 @return the information about the file
545 IN SHELL_FILE_HANDLE FileHandle
548 return (FileFunctionMap
.GetFileInfo(FileHandle
));
552 This function sets the information about the file for the opened handle
555 @param[in] FileHandle The file handle of the file for which information
558 @param[in] FileInfo The information to set.
560 @retval EFI_SUCCESS The information was set.
561 @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
562 @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
563 @retval EFI_NO_MEDIA The device has no medium.
564 @retval EFI_DEVICE_ERROR The device reported an error.
565 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
566 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
567 @retval EFI_ACCESS_DENIED The file was opened read only.
568 @retval EFI_VOLUME_FULL The volume is full.
573 IN SHELL_FILE_HANDLE FileHandle
,
574 IN EFI_FILE_INFO
*FileInfo
577 return (FileFunctionMap
.SetFileInfo(FileHandle
, FileInfo
));
581 This function will open a file or directory referenced by DevicePath.
583 This function opens a file with the open mode according to the file path. The
584 Attributes is valid only for EFI_FILE_MODE_CREATE.
586 @param FilePath on input the device path to the file. On output
587 the remaining device path.
588 @param FileHandle pointer to the file handle.
589 @param OpenMode the mode to open the file with.
590 @param Attributes the file's file attributes.
592 @retval EFI_SUCCESS The information was set.
593 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
594 @retval EFI_UNSUPPORTED Could not open the file path.
595 @retval EFI_NOT_FOUND The specified file could not be found on the
596 device or the file system could not be found on
598 @retval EFI_NO_MEDIA The device has no medium.
599 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
600 medium is no longer supported.
601 @retval EFI_DEVICE_ERROR The device reported an error.
602 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
603 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
604 @retval EFI_ACCESS_DENIED The file was opened read only.
605 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
607 @retval EFI_VOLUME_FULL The volume is full.
611 ShellOpenFileByDevicePath(
612 IN OUT EFI_DEVICE_PATH_PROTOCOL
**FilePath
,
613 OUT SHELL_FILE_HANDLE
*FileHandle
,
620 EFI_FILE_PROTOCOL
*File
;
622 if (FilePath
== NULL
|| FileHandle
== NULL
) {
623 return (EFI_INVALID_PARAMETER
);
627 // which shell interface should we use
629 if (gEfiShellProtocol
!= NULL
) {
631 // use UEFI Shell 2.0 method.
633 FileName
= gEfiShellProtocol
->GetFilePathFromDevicePath(*FilePath
);
634 if (FileName
== NULL
) {
635 return (EFI_INVALID_PARAMETER
);
637 Status
= ShellOpenFileByName(FileName
, FileHandle
, OpenMode
, Attributes
);
644 // use old shell method.
646 Status
= EfiOpenFileByDevicePath (FilePath
, &File
, OpenMode
, Attributes
);
647 if (EFI_ERROR (Status
)) {
652 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
654 *FileHandle
= (VOID
*)File
;
655 return (EFI_SUCCESS
);
659 This function will open a file or directory referenced by filename.
661 If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
662 otherwise, the Filehandle is NULL. The Attributes is valid only for
663 EFI_FILE_MODE_CREATE.
665 if FileName is NULL then ASSERT()
667 @param FileName pointer to file name
668 @param FileHandle pointer to the file handle.
669 @param OpenMode the mode to open the file with.
670 @param Attributes the file's file attributes.
672 @retval EFI_SUCCESS The information was set.
673 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
674 @retval EFI_UNSUPPORTED Could not open the file path.
675 @retval EFI_NOT_FOUND The specified file could not be found on the
676 device or the file system could not be found
678 @retval EFI_NO_MEDIA The device has no medium.
679 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
680 medium is no longer supported.
681 @retval EFI_DEVICE_ERROR The device reported an error.
682 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
683 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
684 @retval EFI_ACCESS_DENIED The file was opened read only.
685 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
687 @retval EFI_VOLUME_FULL The volume is full.
692 IN CONST CHAR16
*FileName
,
693 OUT SHELL_FILE_HANDLE
*FileHandle
,
698 EFI_DEVICE_PATH_PROTOCOL
*FilePath
;
700 EFI_FILE_INFO
*FileInfo
;
701 CHAR16
*FileNameCopy
;
705 // ASSERT if FileName is NULL
707 ASSERT(FileName
!= NULL
);
709 if (FileName
== NULL
) {
710 return (EFI_INVALID_PARAMETER
);
713 if (gEfiShellProtocol
!= NULL
) {
714 if ((OpenMode
& EFI_FILE_MODE_CREATE
) == EFI_FILE_MODE_CREATE
) {
717 // Create only a directory
719 if ((Attributes
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
) {
720 return ShellCreateDirectory(FileName
, FileHandle
);
724 // Create the directory to create the file in
726 FileNameCopy
= AllocateCopyPool (StrSize (FileName
), FileName
);
727 if (FileNameCopy
== NULL
) {
728 return (EFI_OUT_OF_RESOURCES
);
730 PathCleanUpDirectories (FileNameCopy
);
731 if (PathRemoveLastItem (FileNameCopy
)) {
732 if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy
, FileHandle
))) {
733 ShellCloseFile (FileHandle
);
736 SHELL_FREE_NON_NULL (FileNameCopy
);
740 // Use UEFI Shell 2.0 method to create the file
742 Status
= gEfiShellProtocol
->OpenFileByName(FileName
,
745 if (EFI_ERROR(Status
)) {
749 if (mUnicodeCollationProtocol
== NULL
) {
750 Status
= gBS
->LocateProtocol (&gEfiUnicodeCollation2ProtocolGuid
, NULL
, (VOID
**)&mUnicodeCollationProtocol
);
751 if (EFI_ERROR (Status
)) {
752 gEfiShellProtocol
->CloseFile (*FileHandle
);
757 if ((mUnicodeCollationProtocol
->StriColl (mUnicodeCollationProtocol
, (CHAR16
*)FileName
, L
"NUL") != 0) &&
758 (mUnicodeCollationProtocol
->StriColl (mUnicodeCollationProtocol
, (CHAR16
*)FileName
, L
"NULL") != 0) &&
759 !EFI_ERROR(Status
) && ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0)){
760 FileInfo
= FileFunctionMap
.GetFileInfo(*FileHandle
);
761 ASSERT(FileInfo
!= NULL
);
762 FileInfo
->Attribute
= Attributes
;
763 Status2
= FileFunctionMap
.SetFileInfo(*FileHandle
, FileInfo
);
765 if (EFI_ERROR (Status2
)) {
766 gEfiShellProtocol
->CloseFile(*FileHandle
);
773 // Using EFI Shell version
774 // this means convert name to path and call that function
775 // since this will use EFI method again that will open it.
777 ASSERT(mEfiShellEnvironment2
!= NULL
);
778 FilePath
= mEfiShellEnvironment2
->NameToPath ((CHAR16
*)FileName
);
779 if (FilePath
!= NULL
) {
780 return (ShellOpenFileByDevicePath(&FilePath
,
785 return (EFI_DEVICE_ERROR
);
788 This function create a directory
790 If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
791 otherwise, the Filehandle is NULL. If the directory already existed, this
792 function opens the existing directory.
794 @param DirectoryName pointer to directory name
795 @param FileHandle pointer to the file handle.
797 @retval EFI_SUCCESS The information was set.
798 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
799 @retval EFI_UNSUPPORTED Could not open the file path.
800 @retval EFI_NOT_FOUND The specified file could not be found on the
801 device or the file system could not be found
803 @retval EFI_NO_MEDIA The device has no medium.
804 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
805 medium is no longer supported.
806 @retval EFI_DEVICE_ERROR The device reported an error.
807 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
808 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
809 @retval EFI_ACCESS_DENIED The file was opened read only.
810 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
812 @retval EFI_VOLUME_FULL The volume is full.
813 @sa ShellOpenFileByName
817 ShellCreateDirectory(
818 IN CONST CHAR16
*DirectoryName
,
819 OUT SHELL_FILE_HANDLE
*FileHandle
822 if (gEfiShellProtocol
!= NULL
) {
824 // Use UEFI Shell 2.0 method
826 return (gEfiShellProtocol
->CreateFile(DirectoryName
,
831 return (ShellOpenFileByName(DirectoryName
,
833 EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
,
840 This function reads information from an opened file.
842 If FileHandle is not a directory, the function reads the requested number of
843 bytes from the file at the file's current position and returns them in Buffer.
844 If the read goes beyond the end of the file, the read length is truncated to the
845 end of the file. The file's current position is increased by the number of bytes
846 returned. If FileHandle is a directory, the function reads the directory entry
847 at the file's current position and returns the entry in Buffer. If the Buffer
848 is not large enough to hold the current directory entry, then
849 EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
850 BufferSize is set to be the size of the buffer needed to read the entry. On
851 success, the current position is updated to the next directory entry. If there
852 are no more directory entries, the read returns a zero-length buffer.
853 EFI_FILE_INFO is the structure returned as the directory entry.
855 @param FileHandle the opened file handle
856 @param BufferSize on input the size of buffer in bytes. on return
857 the number of bytes written.
858 @param Buffer the buffer to put read data into.
860 @retval EFI_SUCCESS Data was read.
861 @retval EFI_NO_MEDIA The device has no media.
862 @retval EFI_DEVICE_ERROR The device reported an error.
863 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
864 @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
871 IN SHELL_FILE_HANDLE FileHandle
,
872 IN OUT UINTN
*BufferSize
,
876 return (FileFunctionMap
.ReadFile(FileHandle
, BufferSize
, Buffer
));
881 Write data to a file.
883 This function writes the specified number of bytes to the file at the current
884 file position. The current file position is advanced the actual number of bytes
885 written, which is returned in BufferSize. Partial writes only occur when there
886 has been a data error during the write attempt (such as "volume space full").
887 The file is automatically grown to hold the data if required. Direct writes to
888 opened directories are not supported.
890 @param FileHandle The opened file for writing
891 @param BufferSize on input the number of bytes in Buffer. On output
892 the number of bytes written.
893 @param Buffer the buffer containing data to write is stored.
895 @retval EFI_SUCCESS Data was written.
896 @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
897 @retval EFI_NO_MEDIA The device has no media.
898 @retval EFI_DEVICE_ERROR The device reported an error.
899 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
900 @retval EFI_WRITE_PROTECTED The device is write-protected.
901 @retval EFI_ACCESS_DENIED The file was open for read only.
902 @retval EFI_VOLUME_FULL The volume is full.
907 IN SHELL_FILE_HANDLE FileHandle
,
908 IN OUT UINTN
*BufferSize
,
912 return (FileFunctionMap
.WriteFile(FileHandle
, BufferSize
, Buffer
));
916 Close an open file handle.
918 This function closes a specified file handle. All "dirty" cached file data is
919 flushed to the device, and the file is closed. In all cases the handle is
922 @param FileHandle the file handle to close.
924 @retval EFI_SUCCESS the file handle was closed sucessfully.
929 IN SHELL_FILE_HANDLE
*FileHandle
932 return (FileFunctionMap
.CloseFile(*FileHandle
));
936 Delete a file and close the handle
938 This function closes and deletes a file. In all cases the file handle is closed.
939 If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
940 returned, but the handle is still closed.
942 @param FileHandle the file handle to delete
944 @retval EFI_SUCCESS the file was closed sucessfully
945 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
947 @retval INVALID_PARAMETER One of the parameters has an invalid value.
952 IN SHELL_FILE_HANDLE
*FileHandle
955 return (FileFunctionMap
.DeleteFile(*FileHandle
));
959 Set the current position in a file.
961 This function sets the current file position for the handle to the position
962 supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
963 absolute positioning is supported, and seeking past the end of the file is
964 allowed (a subsequent write would grow the file). Seeking to position
965 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
966 If FileHandle is a directory, the only position that may be set is zero. This
967 has the effect of starting the read process of the directory entries over.
969 @param FileHandle The file handle on which the position is being set
970 @param Position Byte position from begining of file
972 @retval EFI_SUCCESS Operation completed sucessfully.
973 @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
975 @retval INVALID_PARAMETER One of the parameters has an invalid value.
979 ShellSetFilePosition (
980 IN SHELL_FILE_HANDLE FileHandle
,
984 return (FileFunctionMap
.SetFilePosition(FileHandle
, Position
));
988 Gets a file's current position
990 This function retrieves the current file position for the file handle. For
991 directories, the current file position has no meaning outside of the file
992 system driver and as such the operation is not supported. An error is returned
993 if FileHandle is a directory.
995 @param FileHandle The open file handle on which to get the position.
996 @param Position Byte position from begining of file.
998 @retval EFI_SUCCESS the operation completed sucessfully.
999 @retval INVALID_PARAMETER One of the parameters has an invalid value.
1000 @retval EFI_UNSUPPORTED the request is not valid on directories.
1004 ShellGetFilePosition (
1005 IN SHELL_FILE_HANDLE FileHandle
,
1006 OUT UINT64
*Position
1009 return (FileFunctionMap
.GetFilePosition(FileHandle
, Position
));
1012 Flushes data on a file
1014 This function flushes all modified data associated with a file to a device.
1016 @param FileHandle The file handle on which to flush data
1018 @retval EFI_SUCCESS The data was flushed.
1019 @retval EFI_NO_MEDIA The device has no media.
1020 @retval EFI_DEVICE_ERROR The device reported an error.
1021 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1022 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
1023 @retval EFI_ACCESS_DENIED The file was opened for read only.
1028 IN SHELL_FILE_HANDLE FileHandle
1031 return (FileFunctionMap
.FlushFile(FileHandle
));
1034 /** Retrieve first entry from a directory.
1036 This function takes an open directory handle and gets information from the
1037 first entry in the directory. A buffer is allocated to contain
1038 the information and a pointer to the buffer is returned in *Buffer. The
1039 caller can use ShellFindNextFile() to get subsequent directory entries.
1041 The buffer will be freed by ShellFindNextFile() when the last directory
1042 entry is read. Otherwise, the caller must free the buffer, using FreePool,
1043 when finished with it.
1045 @param[in] DirHandle The file handle of the directory to search.
1046 @param[out] Buffer The pointer to the buffer for the file's information.
1048 @retval EFI_SUCCESS Found the first file.
1049 @retval EFI_NOT_FOUND Cannot find the directory.
1050 @retval EFI_NO_MEDIA The device has no media.
1051 @retval EFI_DEVICE_ERROR The device reported an error.
1052 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1053 @return Others status of ShellGetFileInfo, ShellSetFilePosition,
1058 ShellFindFirstFile (
1059 IN SHELL_FILE_HANDLE DirHandle
,
1060 OUT EFI_FILE_INFO
**Buffer
1064 // pass to file handle lib
1066 return (FileHandleFindFirstFile(DirHandle
, Buffer
));
1068 /** Retrieve next entries from a directory.
1070 To use this function, the caller must first call the ShellFindFirstFile()
1071 function to get the first directory entry. Subsequent directory entries are
1072 retrieved by using the ShellFindNextFile() function. This function can
1073 be called several times to get each entry from the directory. If the call of
1074 ShellFindNextFile() retrieved the last directory entry, the next call of
1075 this function will set *NoFile to TRUE and free the buffer.
1077 @param[in] DirHandle The file handle of the directory.
1078 @param[out] Buffer The pointer to buffer for file's information.
1079 @param[out] NoFile The pointer to boolean when last file is found.
1081 @retval EFI_SUCCESS Found the next file, or reached last file
1082 @retval EFI_NO_MEDIA The device has no media.
1083 @retval EFI_DEVICE_ERROR The device reported an error.
1084 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1089 IN SHELL_FILE_HANDLE DirHandle
,
1090 OUT EFI_FILE_INFO
*Buffer
,
1095 // pass to file handle lib
1097 return (FileHandleFindNextFile(DirHandle
, Buffer
, NoFile
));
1100 Retrieve the size of a file.
1102 if FileHandle is NULL then ASSERT()
1103 if Size is NULL then ASSERT()
1105 This function extracts the file size info from the FileHandle's EFI_FILE_INFO
1108 @param FileHandle file handle from which size is retrieved
1109 @param Size pointer to size
1111 @retval EFI_SUCCESS operation was completed sucessfully
1112 @retval EFI_DEVICE_ERROR cannot access the file
1117 IN SHELL_FILE_HANDLE FileHandle
,
1121 return (FileFunctionMap
.GetFileSize(FileHandle
, Size
));
1124 Retrieves the status of the break execution flag
1126 this function is useful to check whether the application is being asked to halt by the shell.
1128 @retval TRUE the execution break is enabled
1129 @retval FALSE the execution break is not enabled
1133 ShellGetExecutionBreakFlag(
1138 // Check for UEFI Shell 2.0 protocols
1140 if (gEfiShellProtocol
!= NULL
) {
1143 // We are using UEFI Shell 2.0; see if the event has been triggered
1145 if (gBS
->CheckEvent(gEfiShellProtocol
->ExecutionBreak
) != EFI_SUCCESS
) {
1152 // using EFI Shell; call the function to check
1154 if (mEfiShellEnvironment2
!= NULL
) {
1155 return (mEfiShellEnvironment2
->GetExecutionBreak());
1161 return the value of an environment variable
1163 this function gets the value of the environment variable set by the
1164 ShellSetEnvironmentVariable function
1166 @param EnvKey The key name of the environment variable.
1168 @retval NULL the named environment variable does not exist.
1169 @return != NULL pointer to the value of the environment variable
1173 ShellGetEnvironmentVariable (
1174 IN CONST CHAR16
*EnvKey
1178 // Check for UEFI Shell 2.0 protocols
1180 if (gEfiShellProtocol
!= NULL
) {
1181 return (gEfiShellProtocol
->GetEnv(EnvKey
));
1185 // Check for EFI shell
1187 if (mEfiShellEnvironment2
!= NULL
) {
1188 return (mEfiShellEnvironment2
->GetEnv((CHAR16
*)EnvKey
));
1194 set the value of an environment variable
1196 This function changes the current value of the specified environment variable. If the
1197 environment variable exists and the Value is an empty string, then the environment
1198 variable is deleted. If the environment variable exists and the Value is not an empty
1199 string, then the value of the environment variable is changed. If the environment
1200 variable does not exist and the Value is an empty string, there is no action. If the
1201 environment variable does not exist and the Value is a non-empty string, then the
1202 environment variable is created and assigned the specified value.
1204 This is not supported pre-UEFI Shell 2.0.
1206 @param EnvKey The key name of the environment variable.
1207 @param EnvVal The Value of the environment variable
1208 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
1210 @retval EFI_SUCCESS the operation was completed sucessfully
1211 @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
1215 ShellSetEnvironmentVariable (
1216 IN CONST CHAR16
*EnvKey
,
1217 IN CONST CHAR16
*EnvVal
,
1222 // Check for UEFI Shell 2.0 protocols
1224 if (gEfiShellProtocol
!= NULL
) {
1225 return (gEfiShellProtocol
->SetEnv(EnvKey
, EnvVal
, Volatile
));
1229 // This feature does not exist under EFI shell
1231 return (EFI_UNSUPPORTED
);
1235 Cause the shell to parse and execute a command line.
1237 This function creates a nested instance of the shell and executes the specified
1238 command (CommandLine) with the specified environment (Environment). Upon return,
1239 the status code returned by the specified command is placed in StatusCode.
1240 If Environment is NULL, then the current environment is used and all changes made
1241 by the commands executed will be reflected in the current environment. If the
1242 Environment is non-NULL, then the changes made will be discarded.
1243 The CommandLine is executed from the current working directory on the current
1246 The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
1247 environment. The values pointed to by the parameters will be unchanged by the
1248 ShellExecute() function. The Output parameter has no effect in a
1249 UEFI Shell 2.0 environment.
1251 @param[in] ParentHandle The parent image starting the operation.
1252 @param[in] CommandLine The pointer to a NULL terminated command line.
1253 @param[in] Output True to display debug output. False to hide it.
1254 @param[in] EnvironmentVariables Optional pointer to array of environment variables
1255 in the form "x=y". If NULL, the current set is used.
1256 @param[out] Status The status of the run command line.
1258 @retval EFI_SUCCESS The operation completed sucessfully. Status
1259 contains the status code returned.
1260 @retval EFI_INVALID_PARAMETER A parameter contains an invalid value.
1261 @retval EFI_OUT_OF_RESOURCES Out of resources.
1262 @retval EFI_UNSUPPORTED The operation is not allowed.
1267 IN EFI_HANDLE
*ParentHandle
,
1268 IN CHAR16
*CommandLine OPTIONAL
,
1269 IN BOOLEAN Output OPTIONAL
,
1270 IN CHAR16
**EnvironmentVariables OPTIONAL
,
1271 OUT EFI_STATUS
*Status OPTIONAL
1274 EFI_STATUS CmdStatus
;
1276 // Check for UEFI Shell 2.0 protocols
1278 if (gEfiShellProtocol
!= NULL
) {
1280 // Call UEFI Shell 2.0 version (not using Output parameter)
1282 return (gEfiShellProtocol
->Execute(ParentHandle
,
1284 EnvironmentVariables
,
1289 // Check for EFI shell
1291 if (mEfiShellEnvironment2
!= NULL
) {
1293 // Call EFI Shell version.
1295 // Due to an unfixable bug in the EdkShell implementation, we must
1296 // dereference "ParentHandle" here:
1298 // 1. The EFI shell installs the EFI_SHELL_ENVIRONMENT2 protocol,
1299 // identified by gEfiShellEnvironment2Guid.
1300 // 2. The Execute() member function takes "ParentImageHandle" as first
1301 // parameter, with type (EFI_HANDLE*).
1302 // 3. In the EdkShell implementation, SEnvExecute() implements the
1303 // Execute() member function. It passes "ParentImageHandle" correctly to
1305 // 4. SEnvDoExecute() takes the (EFI_HANDLE*), and passes it directly --
1306 // without de-referencing -- to the HandleProtocol() boot service.
1307 // 5. But HandleProtocol() takes an EFI_HANDLE.
1309 // Therefore we must
1310 // - de-reference "ParentHandle" here, to mask the bug in
1311 // SEnvDoExecute(), and
1312 // - pass the resultant EFI_HANDLE as an (EFI_HANDLE*).
1314 CmdStatus
= (mEfiShellEnvironment2
->Execute((EFI_HANDLE
*)*ParentHandle
,
1318 // No Status output parameter so just use the returned status
1320 if (Status
!= NULL
) {
1321 *Status
= CmdStatus
;
1324 // If there was an error, we can't tell if it was from the command or from
1325 // the Execute() function, so we'll just assume the shell ran successfully
1326 // and the error came from the command.
1331 return (EFI_UNSUPPORTED
);
1335 Retreives the current directory path
1337 If the DeviceName is NULL, it returns the current device's current directory
1338 name. If the DeviceName is not NULL, it returns the current directory name
1341 Note that the current directory string should exclude the tailing backslash character.
1343 @param DeviceName the name of the drive to get directory on
1345 @retval NULL the directory does not exist
1346 @return != NULL the directory
1350 ShellGetCurrentDir (
1351 IN CHAR16
* CONST DeviceName OPTIONAL
1355 // Check for UEFI Shell 2.0 protocols
1357 if (gEfiShellProtocol
!= NULL
) {
1358 return (gEfiShellProtocol
->GetCurDir(DeviceName
));
1362 // Check for EFI shell
1364 if (mEfiShellEnvironment2
!= NULL
) {
1365 return (mEfiShellEnvironment2
->CurDir(DeviceName
));
1371 sets (enabled or disabled) the page break mode
1373 when page break mode is enabled the screen will stop scrolling
1374 and wait for operator input before scrolling a subsequent screen.
1376 @param CurrentState TRUE to enable and FALSE to disable
1380 ShellSetPageBreakMode (
1381 IN BOOLEAN CurrentState
1385 // check for enabling
1387 if (CurrentState
!= 0x00) {
1389 // check for UEFI Shell 2.0
1391 if (gEfiShellProtocol
!= NULL
) {
1393 // Enable with UEFI 2.0 Shell
1395 gEfiShellProtocol
->EnablePageBreak();
1399 // Check for EFI shell
1401 if (mEfiShellEnvironment2
!= NULL
) {
1403 // Enable with EFI Shell
1405 mEfiShellEnvironment2
->EnablePageBreak (DEFAULT_INIT_ROW
, DEFAULT_AUTO_LF
);
1411 // check for UEFI Shell 2.0
1413 if (gEfiShellProtocol
!= NULL
) {
1415 // Disable with UEFI 2.0 Shell
1417 gEfiShellProtocol
->DisablePageBreak();
1421 // Check for EFI shell
1423 if (mEfiShellEnvironment2
!= NULL
) {
1425 // Disable with EFI Shell
1427 mEfiShellEnvironment2
->DisablePageBreak ();
1435 /// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
1436 /// This allows for the struct to be populated.
1443 SHELL_FILE_HANDLE Handle
;
1444 EFI_FILE_INFO
*Info
;
1445 } EFI_SHELL_FILE_INFO_NO_CONST
;
1448 Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
1450 if OldStyleFileList is NULL then ASSERT()
1452 this function will convert a SHELL_FILE_ARG based list into a callee allocated
1453 EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
1454 the ShellCloseFileMetaArg function.
1456 @param[in] FileList the EFI shell list type
1457 @param[in, out] ListHead the list to add to
1459 @retval the resultant head of the double linked new format list;
1462 InternalShellConvertFileListType (
1463 IN LIST_ENTRY
*FileList
,
1464 IN OUT LIST_ENTRY
*ListHead
1467 SHELL_FILE_ARG
*OldInfo
;
1469 EFI_SHELL_FILE_INFO_NO_CONST
*NewInfo
;
1474 ASSERT(FileList
!= NULL
);
1475 ASSERT(ListHead
!= NULL
);
1478 // enumerate through each member of the old list and copy
1480 for (Link
= FileList
->ForwardLink
; Link
!= FileList
; Link
= Link
->ForwardLink
) {
1481 OldInfo
= CR (Link
, SHELL_FILE_ARG
, Link
, SHELL_FILE_ARG_SIGNATURE
);
1482 ASSERT(OldInfo
!= NULL
);
1485 // Skip ones that failed to open...
1487 if (OldInfo
->Status
!= EFI_SUCCESS
) {
1492 // make sure the old list was valid
1494 ASSERT(OldInfo
->Info
!= NULL
);
1495 ASSERT(OldInfo
->FullName
!= NULL
);
1496 ASSERT(OldInfo
->FileName
!= NULL
);
1499 // allocate a new EFI_SHELL_FILE_INFO object
1501 NewInfo
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1502 if (NewInfo
== NULL
) {
1503 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO
**)(&ListHead
));
1509 // copy the simple items
1511 NewInfo
->Handle
= OldInfo
->Handle
;
1512 NewInfo
->Status
= OldInfo
->Status
;
1514 // old shell checks for 0 not NULL
1515 OldInfo
->Handle
= 0;
1518 // allocate new space to copy strings and structure
1520 NewInfo
->FullName
= AllocateCopyPool(StrSize(OldInfo
->FullName
), OldInfo
->FullName
);
1521 NewInfo
->FileName
= AllocateCopyPool(StrSize(OldInfo
->FileName
), OldInfo
->FileName
);
1522 NewInfo
->Info
= AllocateCopyPool((UINTN
)OldInfo
->Info
->Size
, OldInfo
->Info
);
1525 // make sure all the memory allocations were sucessful
1527 if (NULL
== NewInfo
->FullName
|| NewInfo
->FileName
== NULL
|| NewInfo
->Info
== NULL
) {
1529 // Free the partially allocated new node
1531 SHELL_FREE_NON_NULL(NewInfo
->FullName
);
1532 SHELL_FREE_NON_NULL(NewInfo
->FileName
);
1533 SHELL_FREE_NON_NULL(NewInfo
->Info
);
1534 SHELL_FREE_NON_NULL(NewInfo
);
1537 // Free the previously converted stuff
1539 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO
**)(&ListHead
));
1545 // add that to the list
1547 InsertTailList(ListHead
, &NewInfo
->Link
);
1552 Opens a group of files based on a path.
1554 This function uses the Arg to open all the matching files. Each matched
1555 file has a SHELL_FILE_INFO structure to record the file information. These
1556 structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
1557 structures from ListHead to access each file. This function supports wildcards
1558 and will process '?' and '*' as such. the list must be freed with a call to
1559 ShellCloseFileMetaArg().
1561 If you are NOT appending to an existing list *ListHead must be NULL. If
1562 *ListHead is NULL then it must be callee freed.
1564 @param Arg pointer to path string
1565 @param OpenMode mode to open files with
1566 @param ListHead head of linked list of results
1568 @retval EFI_SUCCESS the operation was sucessful and the list head
1569 contains the list of opened files
1570 @return != EFI_SUCCESS the operation failed
1572 @sa InternalShellConvertFileListType
1576 ShellOpenFileMetaArg (
1579 IN OUT EFI_SHELL_FILE_INFO
**ListHead
1583 LIST_ENTRY mOldStyleFileList
;
1584 CHAR16
*CleanFilePathStr
;
1587 // ASSERT that Arg and ListHead are not NULL
1589 ASSERT(Arg
!= NULL
);
1590 ASSERT(ListHead
!= NULL
);
1592 CleanFilePathStr
= NULL
;
1594 Status
= InternalShellStripQuotes (Arg
, &CleanFilePathStr
);
1595 if (EFI_ERROR (Status
)) {
1600 // Check for UEFI Shell 2.0 protocols
1602 if (gEfiShellProtocol
!= NULL
) {
1603 if (*ListHead
== NULL
) {
1604 *ListHead
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1605 if (*ListHead
== NULL
) {
1606 FreePool(CleanFilePathStr
);
1607 return (EFI_OUT_OF_RESOURCES
);
1609 InitializeListHead(&((*ListHead
)->Link
));
1611 Status
= gEfiShellProtocol
->OpenFileList(CleanFilePathStr
,
1614 if (EFI_ERROR(Status
)) {
1615 gEfiShellProtocol
->RemoveDupInFileList(ListHead
);
1617 Status
= gEfiShellProtocol
->RemoveDupInFileList(ListHead
);
1619 if (*ListHead
!= NULL
&& IsListEmpty(&(*ListHead
)->Link
)) {
1620 FreePool(*ListHead
);
1621 FreePool(CleanFilePathStr
);
1623 return (EFI_NOT_FOUND
);
1625 FreePool(CleanFilePathStr
);
1630 // Check for EFI shell
1632 if (mEfiShellEnvironment2
!= NULL
) {
1634 // make sure the list head is initialized
1636 InitializeListHead(&mOldStyleFileList
);
1639 // Get the EFI Shell list of files
1641 Status
= mEfiShellEnvironment2
->FileMetaArg(CleanFilePathStr
, &mOldStyleFileList
);
1642 if (EFI_ERROR(Status
)) {
1644 FreePool(CleanFilePathStr
);
1648 if (*ListHead
== NULL
) {
1649 *ListHead
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1650 if (*ListHead
== NULL
) {
1651 FreePool(CleanFilePathStr
);
1652 return (EFI_OUT_OF_RESOURCES
);
1654 InitializeListHead(&((*ListHead
)->Link
));
1658 // Convert that to equivalent of UEFI Shell 2.0 structure
1660 InternalShellConvertFileListType(&mOldStyleFileList
, &(*ListHead
)->Link
);
1663 // Free the EFI Shell version that was converted.
1665 mEfiShellEnvironment2
->FreeFileList(&mOldStyleFileList
);
1667 if ((*ListHead
)->Link
.ForwardLink
== (*ListHead
)->Link
.BackLink
&& (*ListHead
)->Link
.BackLink
== &((*ListHead
)->Link
)) {
1668 FreePool(*ListHead
);
1670 Status
= EFI_NOT_FOUND
;
1672 FreePool(CleanFilePathStr
);
1676 FreePool(CleanFilePathStr
);
1677 return (EFI_UNSUPPORTED
);
1680 Free the linked list returned from ShellOpenFileMetaArg.
1682 if ListHead is NULL then ASSERT().
1684 @param ListHead the pointer to free.
1686 @retval EFI_SUCCESS the operation was sucessful.
1690 ShellCloseFileMetaArg (
1691 IN OUT EFI_SHELL_FILE_INFO
**ListHead
1697 // ASSERT that ListHead is not NULL
1699 ASSERT(ListHead
!= NULL
);
1702 // Check for UEFI Shell 2.0 protocols
1704 if (gEfiShellProtocol
!= NULL
) {
1705 return (gEfiShellProtocol
->FreeFileList(ListHead
));
1706 } else if (mEfiShellEnvironment2
!= NULL
) {
1708 // Since this is EFI Shell version we need to free our internally made copy
1711 for ( Node
= GetFirstNode(&(*ListHead
)->Link
)
1712 ; *ListHead
!= NULL
&& !IsListEmpty(&(*ListHead
)->Link
)
1713 ; Node
= GetFirstNode(&(*ListHead
)->Link
)) {
1714 RemoveEntryList(Node
);
1715 ((EFI_FILE_PROTOCOL
*)((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->Handle
)->Close(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->Handle
);
1716 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->FullName
);
1717 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->FileName
);
1718 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
)->Info
);
1719 FreePool((EFI_SHELL_FILE_INFO_NO_CONST
*)Node
);
1721 SHELL_FREE_NON_NULL(*ListHead
);
1725 return (EFI_UNSUPPORTED
);
1729 Find a file by searching the CWD and then the path.
1731 If FileName is NULL then ASSERT.
1733 If the return value is not NULL then the memory must be caller freed.
1735 @param FileName Filename string.
1737 @retval NULL the file was not found
1738 @return !NULL the full path to the file.
1743 IN CONST CHAR16
*FileName
1747 SHELL_FILE_HANDLE Handle
;
1751 CONST CHAR16
*Walker
;
1758 // First make sure its not an absolute path.
1760 Status
= ShellOpenFileByName(FileName
, &Handle
, EFI_FILE_MODE_READ
, 0);
1761 if (!EFI_ERROR(Status
)){
1762 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
1763 ASSERT(RetVal
== NULL
);
1764 RetVal
= StrnCatGrow(&RetVal
, NULL
, FileName
, 0);
1765 ShellCloseFile(&Handle
);
1768 ShellCloseFile(&Handle
);
1772 Path
= ShellGetEnvironmentVariable(L
"cwd");
1774 Size
= StrSize(Path
) + sizeof(CHAR16
);
1775 Size
+= StrSize(FileName
);
1776 TestPath
= AllocateZeroPool(Size
);
1777 if (TestPath
== NULL
) {
1780 StrCpyS(TestPath
, Size
/sizeof(CHAR16
), Path
);
1781 StrCatS(TestPath
, Size
/sizeof(CHAR16
), L
"\\");
1782 StrCatS(TestPath
, Size
/sizeof(CHAR16
), FileName
);
1783 Status
= ShellOpenFileByName(TestPath
, &Handle
, EFI_FILE_MODE_READ
, 0);
1784 if (!EFI_ERROR(Status
)){
1785 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
1786 ASSERT(RetVal
== NULL
);
1787 RetVal
= StrnCatGrow(&RetVal
, NULL
, TestPath
, 0);
1788 ShellCloseFile(&Handle
);
1792 ShellCloseFile(&Handle
);
1797 Path
= ShellGetEnvironmentVariable(L
"path");
1799 Size
= StrSize(Path
)+sizeof(CHAR16
);
1800 Size
+= StrSize(FileName
);
1801 TestPath
= AllocateZeroPool(Size
);
1802 if (TestPath
== NULL
) {
1805 Walker
= (CHAR16
*)Path
;
1807 CopyMem(TestPath
, Walker
, StrSize(Walker
));
1808 if (TestPath
!= NULL
) {
1809 TempChar
= StrStr(TestPath
, L
";");
1810 if (TempChar
!= NULL
) {
1811 *TempChar
= CHAR_NULL
;
1813 if (TestPath
[StrLen(TestPath
)-1] != L
'\\') {
1814 StrCatS(TestPath
, Size
/sizeof(CHAR16
), L
"\\");
1816 if (FileName
[0] == L
'\\') {
1819 StrCatS(TestPath
, Size
/sizeof(CHAR16
), FileName
);
1820 if (StrStr(Walker
, L
";") != NULL
) {
1821 Walker
= StrStr(Walker
, L
";") + 1;
1825 Status
= ShellOpenFileByName(TestPath
, &Handle
, EFI_FILE_MODE_READ
, 0);
1826 if (!EFI_ERROR(Status
)){
1827 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
1828 ASSERT(RetVal
== NULL
);
1829 RetVal
= StrnCatGrow(&RetVal
, NULL
, TestPath
, 0);
1830 ShellCloseFile(&Handle
);
1833 ShellCloseFile(&Handle
);
1837 } while (Walker
!= NULL
&& Walker
[0] != CHAR_NULL
);
1844 Find a file by searching the CWD and then the path with a variable set of file
1845 extensions. If the file is not found it will append each extension in the list
1846 in the order provided and return the first one that is successful.
1848 If FileName is NULL, then ASSERT.
1849 If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
1851 If the return value is not NULL then the memory must be caller freed.
1853 @param[in] FileName Filename string.
1854 @param[in] FileExtension Semi-colon delimeted list of possible extensions.
1856 @retval NULL The file was not found.
1857 @retval !NULL The path to the file.
1861 ShellFindFilePathEx (
1862 IN CONST CHAR16
*FileName
,
1863 IN CONST CHAR16
*FileExtension
1868 CONST CHAR16
*ExtensionWalker
;
1873 ASSERT(FileName
!= NULL
);
1874 if (FileExtension
== NULL
) {
1875 return (ShellFindFilePath(FileName
));
1877 RetVal
= ShellFindFilePath(FileName
);
1878 if (RetVal
!= NULL
) {
1881 Size
= StrSize(FileName
);
1882 Size
+= StrSize(FileExtension
);
1883 TestPath
= AllocateZeroPool(Size
);
1884 if (TestPath
== NULL
) {
1887 for (ExtensionWalker
= FileExtension
, TempChar2
= (CHAR16
*)FileExtension
; TempChar2
!= NULL
; ExtensionWalker
= TempChar2
+ 1){
1888 StrCpyS(TestPath
, Size
/sizeof(CHAR16
), FileName
);
1889 if (ExtensionWalker
!= NULL
) {
1890 StrCatS(TestPath
, Size
/sizeof(CHAR16
), ExtensionWalker
);
1892 TempChar
= StrStr(TestPath
, L
";");
1893 if (TempChar
!= NULL
) {
1894 *TempChar
= CHAR_NULL
;
1896 RetVal
= ShellFindFilePath(TestPath
);
1897 if (RetVal
!= NULL
) {
1900 ASSERT(ExtensionWalker
!= NULL
);
1901 TempChar2
= StrStr(ExtensionWalker
, L
";");
1910 SHELL_PARAM_TYPE Type
;
1912 UINTN OriginalPosition
;
1913 } SHELL_PARAM_PACKAGE
;
1916 Checks the list of valid arguments and returns TRUE if the item was found. If the
1917 return value is TRUE then the type parameter is set also.
1919 if CheckList is NULL then ASSERT();
1920 if Name is NULL then ASSERT();
1921 if Type is NULL then ASSERT();
1923 @param Name pointer to Name of parameter found
1924 @param CheckList List to check against
1925 @param Type pointer to type of parameter if it was found
1927 @retval TRUE the Parameter was found. Type is valid.
1928 @retval FALSE the Parameter was not found. Type is not valid.
1931 InternalIsOnCheckList (
1932 IN CONST CHAR16
*Name
,
1933 IN CONST SHELL_PARAM_ITEM
*CheckList
,
1934 OUT SHELL_PARAM_TYPE
*Type
1937 SHELL_PARAM_ITEM
*TempListItem
;
1941 // ASSERT that all 3 pointer parameters aren't NULL
1943 ASSERT(CheckList
!= NULL
);
1944 ASSERT(Type
!= NULL
);
1945 ASSERT(Name
!= NULL
);
1948 // question mark and page break mode are always supported
1950 if ((StrCmp(Name
, L
"-?") == 0) ||
1951 (StrCmp(Name
, L
"-b") == 0)
1958 // Enumerate through the list
1960 for (TempListItem
= (SHELL_PARAM_ITEM
*)CheckList
; TempListItem
->Name
!= NULL
; TempListItem
++) {
1962 // If the Type is TypeStart only check the first characters of the passed in param
1963 // If it matches set the type and return TRUE
1965 if (TempListItem
->Type
== TypeStart
) {
1966 if (StrnCmp(Name
, TempListItem
->Name
, StrLen(TempListItem
->Name
)) == 0) {
1967 *Type
= TempListItem
->Type
;
1971 TempString
= StrnCatGrow(&TempString
, NULL
, Name
, StrLen(TempListItem
->Name
));
1972 if (TempString
!= NULL
) {
1973 if (StringNoCaseCompare(&TempString
, &TempListItem
->Name
) == 0) {
1974 *Type
= TempListItem
->Type
;
1975 FreePool(TempString
);
1978 FreePool(TempString
);
1980 } else if (StringNoCaseCompare(&Name
, &TempListItem
->Name
) == 0) {
1981 *Type
= TempListItem
->Type
;
1989 Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'
1991 @param[in] Name pointer to Name of parameter found
1992 @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
1993 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
1995 @retval TRUE the Parameter is a flag.
1996 @retval FALSE the Parameter not a flag.
2000 IN CONST CHAR16
*Name
,
2001 IN CONST BOOLEAN AlwaysAllowNumbers
,
2002 IN CONST BOOLEAN TimeNumbers
2006 // ASSERT that Name isn't NULL
2008 ASSERT(Name
!= NULL
);
2011 // If we accept numbers then dont return TRUE. (they will be values)
2013 if (((Name
[0] == L
'-' || Name
[0] == L
'+') && InternalShellIsHexOrDecimalNumber(Name
+1, FALSE
, FALSE
, TimeNumbers
)) && AlwaysAllowNumbers
) {
2018 // If the Name has a /, +, or - as the first character return TRUE
2020 if ((Name
[0] == L
'/') ||
2021 (Name
[0] == L
'-') ||
2030 Checks the command line arguments passed against the list of valid ones.
2032 If no initialization is required, then return RETURN_SUCCESS.
2034 @param[in] CheckList pointer to list of parameters to check
2035 @param[out] CheckPackage pointer to pointer to list checked values
2036 @param[out] ProblemParam optional pointer to pointer to unicode string for
2037 the paramater that caused failure. If used then the
2038 caller is responsible for freeing the memory.
2039 @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
2040 @param[in] Argv pointer to array of parameters
2041 @param[in] Argc Count of parameters in Argv
2042 @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
2044 @retval EFI_SUCCESS The operation completed sucessfully.
2045 @retval EFI_OUT_OF_RESOURCES A memory allocation failed
2046 @retval EFI_INVALID_PARAMETER A parameter was invalid
2047 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
2048 duplicated. the duplicated command line argument
2049 was returned in ProblemParam if provided.
2050 @retval EFI_NOT_FOUND a argument required a value that was missing.
2051 the invalid command line argument was returned in
2052 ProblemParam if provided.
2055 InternalCommandLineParse (
2056 IN CONST SHELL_PARAM_ITEM
*CheckList
,
2057 OUT LIST_ENTRY
**CheckPackage
,
2058 OUT CHAR16
**ProblemParam OPTIONAL
,
2059 IN BOOLEAN AutoPageBreak
,
2060 IN CONST CHAR16
**Argv
,
2062 IN BOOLEAN AlwaysAllowNumbers
2066 SHELL_PARAM_TYPE CurrentItemType
;
2067 SHELL_PARAM_PACKAGE
*CurrentItemPackage
;
2071 CONST CHAR16
*TempPointer
;
2072 UINTN CurrentValueSize
;
2075 CurrentItemPackage
= NULL
;
2081 // If there is only 1 item we dont need to do anything
2084 *CheckPackage
= NULL
;
2085 return (EFI_SUCCESS
);
2091 ASSERT(CheckList
!= NULL
);
2092 ASSERT(Argv
!= NULL
);
2095 // initialize the linked list
2097 *CheckPackage
= (LIST_ENTRY
*)AllocateZeroPool(sizeof(LIST_ENTRY
));
2098 if (*CheckPackage
== NULL
) {
2099 return (EFI_OUT_OF_RESOURCES
);
2102 InitializeListHead(*CheckPackage
);
2105 // loop through each of the arguments
2107 for (LoopCounter
= 0 ; LoopCounter
< Argc
; ++LoopCounter
) {
2108 if (Argv
[LoopCounter
] == NULL
) {
2110 // do nothing for NULL argv
2112 } else if (InternalIsOnCheckList(Argv
[LoopCounter
], CheckList
, &CurrentItemType
)) {
2114 // We might have leftover if last parameter didnt have optional value
2116 if (GetItemValue
!= 0) {
2118 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2123 CurrentItemPackage
= AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE
));
2124 if (CurrentItemPackage
== NULL
) {
2125 ShellCommandLineFreeVarList(*CheckPackage
);
2126 *CheckPackage
= NULL
;
2127 return (EFI_OUT_OF_RESOURCES
);
2129 CurrentItemPackage
->Name
= AllocateCopyPool(StrSize(Argv
[LoopCounter
]), Argv
[LoopCounter
]);
2130 if (CurrentItemPackage
->Name
== NULL
) {
2131 ShellCommandLineFreeVarList(*CheckPackage
);
2132 *CheckPackage
= NULL
;
2133 return (EFI_OUT_OF_RESOURCES
);
2135 CurrentItemPackage
->Type
= CurrentItemType
;
2136 CurrentItemPackage
->OriginalPosition
= (UINTN
)(-1);
2137 CurrentItemPackage
->Value
= NULL
;
2140 // Does this flag require a value
2142 switch (CurrentItemPackage
->Type
) {
2144 // possibly trigger the next loop(s) to populate the value of this item
2151 case TypeDoubleValue
:
2156 GetItemValue
= (UINTN
)(-1);
2161 // this item has no value expected; we are done
2163 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2164 ASSERT(GetItemValue
== 0);
2167 } else if (GetItemValue
!= 0 && CurrentItemPackage
!= NULL
&& !InternalIsFlag(Argv
[LoopCounter
], AlwaysAllowNumbers
, (BOOLEAN
)(CurrentItemPackage
->Type
== TypeTimeValue
))) {
2169 // get the item VALUE for a previous flag
2171 CurrentValueSize
= ValueSize
+ StrSize(Argv
[LoopCounter
]) + sizeof(CHAR16
);
2172 NewValue
= ReallocatePool(ValueSize
, CurrentValueSize
, CurrentItemPackage
->Value
);
2173 if (NewValue
== NULL
) {
2174 SHELL_FREE_NON_NULL (CurrentItemPackage
->Value
);
2175 SHELL_FREE_NON_NULL (CurrentItemPackage
);
2176 ShellCommandLineFreeVarList (*CheckPackage
);
2177 *CheckPackage
= NULL
;
2178 return EFI_OUT_OF_RESOURCES
;
2180 CurrentItemPackage
->Value
= NewValue
;
2181 if (ValueSize
== 0) {
2182 StrCpyS( CurrentItemPackage
->Value
,
2183 CurrentValueSize
/sizeof(CHAR16
),
2187 StrCatS( CurrentItemPackage
->Value
,
2188 CurrentValueSize
/sizeof(CHAR16
),
2191 StrCatS( CurrentItemPackage
->Value
,
2192 CurrentValueSize
/sizeof(CHAR16
),
2196 ValueSize
+= StrSize(Argv
[LoopCounter
]) + sizeof(CHAR16
);
2199 if (GetItemValue
== 0) {
2200 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2202 } else if (!InternalIsFlag(Argv
[LoopCounter
], AlwaysAllowNumbers
, FALSE
)){
2204 // add this one as a non-flag
2207 TempPointer
= Argv
[LoopCounter
];
2208 if ((*TempPointer
== L
'^' && *(TempPointer
+1) == L
'-')
2209 || (*TempPointer
== L
'^' && *(TempPointer
+1) == L
'/')
2210 || (*TempPointer
== L
'^' && *(TempPointer
+1) == L
'+')
2214 CurrentItemPackage
= AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE
));
2215 if (CurrentItemPackage
== NULL
) {
2216 ShellCommandLineFreeVarList(*CheckPackage
);
2217 *CheckPackage
= NULL
;
2218 return (EFI_OUT_OF_RESOURCES
);
2220 CurrentItemPackage
->Name
= NULL
;
2221 CurrentItemPackage
->Type
= TypePosition
;
2222 CurrentItemPackage
->Value
= AllocateCopyPool(StrSize(TempPointer
), TempPointer
);
2223 if (CurrentItemPackage
->Value
== NULL
) {
2224 ShellCommandLineFreeVarList(*CheckPackage
);
2225 *CheckPackage
= NULL
;
2226 return (EFI_OUT_OF_RESOURCES
);
2228 CurrentItemPackage
->OriginalPosition
= Count
++;
2229 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2232 // this was a non-recognised flag... error!
2234 if (ProblemParam
!= NULL
) {
2235 *ProblemParam
= AllocateCopyPool(StrSize(Argv
[LoopCounter
]), Argv
[LoopCounter
]);
2237 ShellCommandLineFreeVarList(*CheckPackage
);
2238 *CheckPackage
= NULL
;
2239 return (EFI_VOLUME_CORRUPTED
);
2242 if (GetItemValue
!= 0) {
2244 InsertHeadList(*CheckPackage
, &CurrentItemPackage
->Link
);
2247 // support for AutoPageBreak
2249 if (AutoPageBreak
&& ShellCommandLineGetFlag(*CheckPackage
, L
"-b")) {
2250 ShellSetPageBreakMode(TRUE
);
2252 return (EFI_SUCCESS
);
2256 Checks the command line arguments passed against the list of valid ones.
2257 Optionally removes NULL values first.
2259 If no initialization is required, then return RETURN_SUCCESS.
2261 @param[in] CheckList The pointer to list of parameters to check.
2262 @param[out] CheckPackage The package of checked values.
2263 @param[out] ProblemParam Optional pointer to pointer to unicode string for
2264 the paramater that caused failure.
2265 @param[in] AutoPageBreak Will automatically set PageBreakEnabled.
2266 @param[in] AlwaysAllowNumbers Will never fail for number based flags.
2268 @retval EFI_SUCCESS The operation completed sucessfully.
2269 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2270 @retval EFI_INVALID_PARAMETER A parameter was invalid.
2271 @retval EFI_VOLUME_CORRUPTED The command line was corrupt.
2272 @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One
2273 of the command line arguments was returned in
2274 ProblemParam if provided.
2275 @retval EFI_NOT_FOUND A argument required a value that was missing.
2276 The invalid command line argument was returned in
2277 ProblemParam if provided.
2281 ShellCommandLineParseEx (
2282 IN CONST SHELL_PARAM_ITEM
*CheckList
,
2283 OUT LIST_ENTRY
**CheckPackage
,
2284 OUT CHAR16
**ProblemParam OPTIONAL
,
2285 IN BOOLEAN AutoPageBreak
,
2286 IN BOOLEAN AlwaysAllowNumbers
2290 // ASSERT that CheckList and CheckPackage aren't NULL
2292 ASSERT(CheckList
!= NULL
);
2293 ASSERT(CheckPackage
!= NULL
);
2296 // Check for UEFI Shell 2.0 protocols
2298 if (gEfiShellParametersProtocol
!= NULL
) {
2299 return (InternalCommandLineParse(CheckList
,
2303 (CONST CHAR16
**) gEfiShellParametersProtocol
->Argv
,
2304 gEfiShellParametersProtocol
->Argc
,
2305 AlwaysAllowNumbers
));
2309 // ASSERT That EFI Shell is not required
2311 ASSERT (mEfiShellInterface
!= NULL
);
2312 return (InternalCommandLineParse(CheckList
,
2316 (CONST CHAR16
**) mEfiShellInterface
->Argv
,
2317 mEfiShellInterface
->Argc
,
2318 AlwaysAllowNumbers
));
2322 Frees shell variable list that was returned from ShellCommandLineParse.
2324 This function will free all the memory that was used for the CheckPackage
2325 list of postprocessed shell arguments.
2327 this function has no return value.
2329 if CheckPackage is NULL, then return
2331 @param CheckPackage the list to de-allocate
2335 ShellCommandLineFreeVarList (
2336 IN LIST_ENTRY
*CheckPackage
2342 // check for CheckPackage == NULL
2344 if (CheckPackage
== NULL
) {
2349 // for each node in the list
2351 for ( Node
= GetFirstNode(CheckPackage
)
2352 ; !IsListEmpty(CheckPackage
)
2353 ; Node
= GetFirstNode(CheckPackage
)
2356 // Remove it from the list
2358 RemoveEntryList(Node
);
2361 // if it has a name free the name
2363 if (((SHELL_PARAM_PACKAGE
*)Node
)->Name
!= NULL
) {
2364 FreePool(((SHELL_PARAM_PACKAGE
*)Node
)->Name
);
2368 // if it has a value free the value
2370 if (((SHELL_PARAM_PACKAGE
*)Node
)->Value
!= NULL
) {
2371 FreePool(((SHELL_PARAM_PACKAGE
*)Node
)->Value
);
2375 // free the node structure
2377 FreePool((SHELL_PARAM_PACKAGE
*)Node
);
2380 // free the list head node
2382 FreePool(CheckPackage
);
2385 Checks for presence of a flag parameter
2387 flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
2389 if CheckPackage is NULL then return FALSE.
2390 if KeyString is NULL then ASSERT()
2392 @param CheckPackage The package of parsed command line arguments
2393 @param KeyString the Key of the command line argument to check for
2395 @retval TRUE the flag is on the command line
2396 @retval FALSE the flag is not on the command line
2400 ShellCommandLineGetFlag (
2401 IN CONST LIST_ENTRY
* CONST CheckPackage
,
2402 IN CONST CHAR16
* CONST KeyString
2409 // return FALSE for no package or KeyString is NULL
2411 if (CheckPackage
== NULL
|| KeyString
== NULL
) {
2416 // enumerate through the list of parametrs
2418 for ( Node
= GetFirstNode(CheckPackage
)
2419 ; !IsNull (CheckPackage
, Node
)
2420 ; Node
= GetNextNode(CheckPackage
, Node
)
2423 // If the Name matches, return TRUE (and there may be NULL name)
2425 if (((SHELL_PARAM_PACKAGE
*)Node
)->Name
!= NULL
) {
2427 // If Type is TypeStart then only compare the begining of the strings
2429 if (((SHELL_PARAM_PACKAGE
*)Node
)->Type
== TypeStart
) {
2430 if (StrnCmp(KeyString
, ((SHELL_PARAM_PACKAGE
*)Node
)->Name
, StrLen(KeyString
)) == 0) {
2434 TempString
= StrnCatGrow(&TempString
, NULL
, KeyString
, StrLen(((SHELL_PARAM_PACKAGE
*)Node
)->Name
));
2435 if (TempString
!= NULL
) {
2436 if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2437 FreePool(TempString
);
2440 FreePool(TempString
);
2442 } else if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2450 Returns value from command line argument.
2452 Value parameters are in the form of "-<Key> value" or "/<Key> value".
2454 If CheckPackage is NULL, then return NULL.
2456 @param[in] CheckPackage The package of parsed command line arguments.
2457 @param[in] KeyString The Key of the command line argument to check for.
2459 @retval NULL The flag is not on the command line.
2460 @retval !=NULL The pointer to unicode string of the value.
2464 ShellCommandLineGetValue (
2465 IN CONST LIST_ENTRY
*CheckPackage
,
2466 IN CHAR16
*KeyString
2473 // return NULL for no package or KeyString is NULL
2475 if (CheckPackage
== NULL
|| KeyString
== NULL
) {
2480 // enumerate through the list of parametrs
2482 for ( Node
= GetFirstNode(CheckPackage
)
2483 ; !IsNull (CheckPackage
, Node
)
2484 ; Node
= GetNextNode(CheckPackage
, Node
)
2487 // If the Name matches, return TRUE (and there may be NULL name)
2489 if (((SHELL_PARAM_PACKAGE
*)Node
)->Name
!= NULL
) {
2491 // If Type is TypeStart then only compare the begining of the strings
2493 if (((SHELL_PARAM_PACKAGE
*)Node
)->Type
== TypeStart
) {
2494 if (StrnCmp(KeyString
, ((SHELL_PARAM_PACKAGE
*)Node
)->Name
, StrLen(KeyString
)) == 0) {
2495 return (((SHELL_PARAM_PACKAGE
*)Node
)->Name
+ StrLen(KeyString
));
2498 TempString
= StrnCatGrow(&TempString
, NULL
, KeyString
, StrLen(((SHELL_PARAM_PACKAGE
*)Node
)->Name
));
2499 if (TempString
!= NULL
) {
2500 if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2501 FreePool(TempString
);
2502 return (((SHELL_PARAM_PACKAGE
*)Node
)->Name
+ StrLen(KeyString
));
2504 FreePool(TempString
);
2506 } else if (StringNoCaseCompare(&KeyString
, &((SHELL_PARAM_PACKAGE
*)Node
)->Name
) == 0) {
2507 return (((SHELL_PARAM_PACKAGE
*)Node
)->Value
);
2515 Returns raw value from command line argument.
2517 Raw value parameters are in the form of "value" in a specific position in the list.
2519 If CheckPackage is NULL, then return NULL.
2521 @param[in] CheckPackage The package of parsed command line arguments.
2522 @param[in] Position The position of the value.
2524 @retval NULL The flag is not on the command line.
2525 @retval !=NULL The pointer to unicode string of the value.
2529 ShellCommandLineGetRawValue (
2530 IN CONST LIST_ENTRY
* CONST CheckPackage
,
2537 // check for CheckPackage == NULL
2539 if (CheckPackage
== NULL
) {
2544 // enumerate through the list of parametrs
2546 for ( Node
= GetFirstNode(CheckPackage
)
2547 ; !IsNull (CheckPackage
, Node
)
2548 ; Node
= GetNextNode(CheckPackage
, Node
)
2551 // If the position matches, return the value
2553 if (((SHELL_PARAM_PACKAGE
*)Node
)->OriginalPosition
== Position
) {
2554 return (((SHELL_PARAM_PACKAGE
*)Node
)->Value
);
2561 returns the number of command line value parameters that were parsed.
2563 this will not include flags.
2565 @param[in] CheckPackage The package of parsed command line arguments.
2567 @retval (UINTN)-1 No parsing has ocurred
2568 @return other The number of value parameters found
2572 ShellCommandLineGetCount(
2573 IN CONST LIST_ENTRY
*CheckPackage
2579 if (CheckPackage
== NULL
) {
2582 for ( Node1
= GetFirstNode(CheckPackage
), Count
= 0
2583 ; !IsNull (CheckPackage
, Node1
)
2584 ; Node1
= GetNextNode(CheckPackage
, Node1
)
2586 if (((SHELL_PARAM_PACKAGE
*)Node1
)->Name
== NULL
) {
2594 Determines if a parameter is duplicated.
2596 If Param is not NULL then it will point to a callee allocated string buffer
2597 with the parameter value if a duplicate is found.
2599 If CheckPackage is NULL, then ASSERT.
2601 @param[in] CheckPackage The package of parsed command line arguments.
2602 @param[out] Param Upon finding one, a pointer to the duplicated parameter.
2604 @retval EFI_SUCCESS No parameters were duplicated.
2605 @retval EFI_DEVICE_ERROR A duplicate was found.
2609 ShellCommandLineCheckDuplicate (
2610 IN CONST LIST_ENTRY
*CheckPackage
,
2617 ASSERT(CheckPackage
!= NULL
);
2619 for ( Node1
= GetFirstNode(CheckPackage
)
2620 ; !IsNull (CheckPackage
, Node1
)
2621 ; Node1
= GetNextNode(CheckPackage
, Node1
)
2623 for ( Node2
= GetNextNode(CheckPackage
, Node1
)
2624 ; !IsNull (CheckPackage
, Node2
)
2625 ; Node2
= GetNextNode(CheckPackage
, Node2
)
2627 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) {
2628 if (Param
!= NULL
) {
2630 *Param
= StrnCatGrow(Param
, NULL
, ((SHELL_PARAM_PACKAGE
*)Node1
)->Name
, 0);
2632 return (EFI_DEVICE_ERROR
);
2636 return (EFI_SUCCESS
);
2640 This is a find and replace function. Upon successful return the NewString is a copy of
2641 SourceString with each instance of FindTarget replaced with ReplaceWith.
2643 If SourceString and NewString overlap the behavior is undefined.
2645 If the string would grow bigger than NewSize it will halt and return error.
2647 @param[in] SourceString The string with source buffer.
2648 @param[in, out] NewString The string with resultant buffer.
2649 @param[in] NewSize The size in bytes of NewString.
2650 @param[in] FindTarget The string to look for.
2651 @param[in] ReplaceWith The string to replace FindTarget with.
2652 @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'
2653 immediately before it.
2654 @param[in] ParameterReplacing If TRUE will add "" around items with spaces.
2656 @retval EFI_INVALID_PARAMETER SourceString was NULL.
2657 @retval EFI_INVALID_PARAMETER NewString was NULL.
2658 @retval EFI_INVALID_PARAMETER FindTarget was NULL.
2659 @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.
2660 @retval EFI_INVALID_PARAMETER FindTarget had length < 1.
2661 @retval EFI_INVALID_PARAMETER SourceString had length < 1.
2662 @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold
2663 the new string (truncation occurred).
2664 @retval EFI_SUCCESS The string was successfully copied with replacement.
2668 ShellCopySearchAndReplace(
2669 IN CHAR16 CONST
*SourceString
,
2670 IN OUT CHAR16
*NewString
,
2672 IN CONST CHAR16
*FindTarget
,
2673 IN CONST CHAR16
*ReplaceWith
,
2674 IN CONST BOOLEAN SkipPreCarrot
,
2675 IN CONST BOOLEAN ParameterReplacing
2681 if ( (SourceString
== NULL
)
2682 || (NewString
== NULL
)
2683 || (FindTarget
== NULL
)
2684 || (ReplaceWith
== NULL
)
2685 || (StrLen(FindTarget
) < 1)
2686 || (StrLen(SourceString
) < 1)
2688 return (EFI_INVALID_PARAMETER
);
2691 if (StrStr(ReplaceWith
, L
" ") == NULL
|| !ParameterReplacing
) {
2692 Replace
= StrnCatGrow(&Replace
, NULL
, ReplaceWith
, 0);
2694 Replace
= AllocateZeroPool(StrSize(ReplaceWith
) + 2*sizeof(CHAR16
));
2695 if (Replace
!= NULL
) {
2696 UnicodeSPrint(Replace
, StrSize(ReplaceWith
) + 2*sizeof(CHAR16
), L
"\"%s\"", ReplaceWith
);
2699 if (Replace
== NULL
) {
2700 return (EFI_OUT_OF_RESOURCES
);
2702 NewString
= ZeroMem(NewString
, NewSize
);
2703 while (*SourceString
!= CHAR_NULL
) {
2705 // if we find the FindTarget and either Skip == FALSE or Skip and we
2706 // dont have a carrot do a replace...
2708 if (StrnCmp(SourceString
, FindTarget
, StrLen(FindTarget
)) == 0
2709 && ((SkipPreCarrot
&& *(SourceString
-1) != L
'^') || !SkipPreCarrot
)
2711 SourceString
+= StrLen(FindTarget
);
2712 Size
= StrSize(NewString
);
2713 if ((Size
+ (StrLen(Replace
)*sizeof(CHAR16
))) > NewSize
) {
2715 return (EFI_BUFFER_TOO_SMALL
);
2717 StrCatS(NewString
, NewSize
/sizeof(CHAR16
), Replace
);
2719 Size
= StrSize(NewString
);
2720 if (Size
+ sizeof(CHAR16
) > NewSize
) {
2722 return (EFI_BUFFER_TOO_SMALL
);
2724 StrnCatS(NewString
, NewSize
/sizeof(CHAR16
), SourceString
, 1);
2729 return (EFI_SUCCESS
);
2733 Internal worker function to output a string.
2735 This function will output a string to the correct StdOut.
2737 @param[in] String The string to print out.
2739 @retval EFI_SUCCESS The operation was sucessful.
2740 @retval !EFI_SUCCESS The operation failed.
2744 IN CONST CHAR16
*String
2748 Size
= StrSize(String
) - sizeof(CHAR16
);
2750 return (EFI_SUCCESS
);
2752 if (gEfiShellParametersProtocol
!= NULL
) {
2753 return (gEfiShellProtocol
->WriteFile(gEfiShellParametersProtocol
->StdOut
, &Size
, (VOID
*)String
));
2755 if (mEfiShellInterface
!= NULL
) {
2756 if (mEfiShellInterface
->RedirArgc
== 0) {
2758 // Divide in half for old shell. Must be string length not size.
2760 Size
/=2; // Divide in half only when no redirection.
2762 return (mEfiShellInterface
->StdOut
->Write(mEfiShellInterface
->StdOut
, &Size
, (VOID
*)String
));
2765 return (EFI_UNSUPPORTED
);
2769 Print at a specific location on the screen.
2771 This function will move the cursor to a given screen location and print the specified string
2773 If -1 is specified for either the Row or Col the current screen location for BOTH
2776 if either Row or Col is out of range for the current console, then ASSERT
2777 if Format is NULL, then ASSERT
2779 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2780 the following additional flags:
2781 %N - Set output attribute to normal
2782 %H - Set output attribute to highlight
2783 %E - Set output attribute to error
2784 %B - Set output attribute to blue color
2785 %V - Set output attribute to green color
2787 Note: The background color is controlled by the shell command cls.
2789 @param[in] Col the column to print at
2790 @param[in] Row the row to print at
2791 @param[in] Format the format string
2792 @param[in] Marker the marker for the variable argument list
2794 @return EFI_SUCCESS The operation was successful.
2795 @return EFI_DEVICE_ERROR The console device reported an error.
2798 InternalShellPrintWorker(
2799 IN INT32 Col OPTIONAL
,
2800 IN INT32 Row OPTIONAL
,
2801 IN CONST CHAR16
*Format
,
2806 CHAR16
*ResumeLocation
;
2807 CHAR16
*FormatWalker
;
2808 UINTN OriginalAttribute
;
2809 CHAR16
*mPostReplaceFormat
;
2810 CHAR16
*mPostReplaceFormat2
;
2812 mPostReplaceFormat
= AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize
));
2813 mPostReplaceFormat2
= AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize
));
2815 if (mPostReplaceFormat
== NULL
|| mPostReplaceFormat2
== NULL
) {
2816 SHELL_FREE_NON_NULL(mPostReplaceFormat
);
2817 SHELL_FREE_NON_NULL(mPostReplaceFormat2
);
2818 return (EFI_OUT_OF_RESOURCES
);
2821 Status
= EFI_SUCCESS
;
2822 OriginalAttribute
= gST
->ConOut
->Mode
->Attribute
;
2825 // Back and forth each time fixing up 1 of our flags...
2827 Status
= ShellCopySearchAndReplace(Format
, mPostReplaceFormat
, PcdGet16 (PcdShellPrintBufferSize
), L
"%N", L
"%%N", FALSE
, FALSE
);
2828 ASSERT_EFI_ERROR(Status
);
2829 Status
= ShellCopySearchAndReplace(mPostReplaceFormat
, mPostReplaceFormat2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%E", L
"%%E", FALSE
, FALSE
);
2830 ASSERT_EFI_ERROR(Status
);
2831 Status
= ShellCopySearchAndReplace(mPostReplaceFormat2
, mPostReplaceFormat
, PcdGet16 (PcdShellPrintBufferSize
), L
"%H", L
"%%H", FALSE
, FALSE
);
2832 ASSERT_EFI_ERROR(Status
);
2833 Status
= ShellCopySearchAndReplace(mPostReplaceFormat
, mPostReplaceFormat2
, PcdGet16 (PcdShellPrintBufferSize
), L
"%B", L
"%%B", FALSE
, FALSE
);
2834 ASSERT_EFI_ERROR(Status
);
2835 Status
= ShellCopySearchAndReplace(mPostReplaceFormat2
, mPostReplaceFormat
, PcdGet16 (PcdShellPrintBufferSize
), L
"%V", L
"%%V", FALSE
, FALSE
);
2836 ASSERT_EFI_ERROR(Status
);
2839 // Use the last buffer from replacing to print from...
2841 UnicodeVSPrint (mPostReplaceFormat2
, PcdGet16 (PcdShellPrintBufferSize
), mPostReplaceFormat
, Marker
);
2843 if (Col
!= -1 && Row
!= -1) {
2844 Status
= gST
->ConOut
->SetCursorPosition(gST
->ConOut
, Col
, Row
);
2847 FormatWalker
= mPostReplaceFormat2
;
2848 while (*FormatWalker
!= CHAR_NULL
) {
2850 // Find the next attribute change request
2852 ResumeLocation
= StrStr(FormatWalker
, L
"%");
2853 if (ResumeLocation
!= NULL
) {
2854 *ResumeLocation
= CHAR_NULL
;
2857 // print the current FormatWalker string
2859 if (StrLen(FormatWalker
)>0) {
2860 Status
= InternalPrintTo(FormatWalker
);
2861 if (EFI_ERROR(Status
)) {
2867 // update the attribute
2869 if (ResumeLocation
!= NULL
) {
2870 if ((ResumeLocation
!= mPostReplaceFormat2
) && (*(ResumeLocation
-1) == L
'^')) {
2872 // Move cursor back 1 position to overwrite the ^
2874 gST
->ConOut
->SetCursorPosition(gST
->ConOut
, gST
->ConOut
->Mode
->CursorColumn
- 1, gST
->ConOut
->Mode
->CursorRow
);
2877 // Print a simple '%' symbol
2879 Status
= InternalPrintTo(L
"%");
2880 ResumeLocation
= ResumeLocation
- 1;
2882 switch (*(ResumeLocation
+1)) {
2884 gST
->ConOut
->SetAttribute(gST
->ConOut
, OriginalAttribute
);
2887 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_YELLOW
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2890 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_WHITE
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2893 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_LIGHTBLUE
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2896 gST
->ConOut
->SetAttribute(gST
->ConOut
, EFI_TEXT_ATTR(EFI_LIGHTGREEN
, ((OriginalAttribute
&(BIT4
|BIT5
|BIT6
))>>4)));
2900 // Print a simple '%' symbol
2902 Status
= InternalPrintTo(L
"%");
2903 if (EFI_ERROR(Status
)) {
2906 ResumeLocation
= ResumeLocation
- 1;
2912 // reset to normal now...
2918 // update FormatWalker to Resume + 2 (skip the % and the indicator)
2920 FormatWalker
= ResumeLocation
+ 2;
2923 gST
->ConOut
->SetAttribute(gST
->ConOut
, OriginalAttribute
);
2925 SHELL_FREE_NON_NULL(mPostReplaceFormat
);
2926 SHELL_FREE_NON_NULL(mPostReplaceFormat2
);
2931 Print at a specific location on the screen.
2933 This function will move the cursor to a given screen location and print the specified string.
2935 If -1 is specified for either the Row or Col the current screen location for BOTH
2938 If either Row or Col is out of range for the current console, then ASSERT.
2939 If Format is NULL, then ASSERT.
2941 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2942 the following additional flags:
2943 %N - Set output attribute to normal
2944 %H - Set output attribute to highlight
2945 %E - Set output attribute to error
2946 %B - Set output attribute to blue color
2947 %V - Set output attribute to green color
2949 Note: The background color is controlled by the shell command cls.
2951 @param[in] Col the column to print at
2952 @param[in] Row the row to print at
2953 @param[in] Format the format string
2954 @param[in] ... The variable argument list.
2956 @return EFI_SUCCESS The printing was successful.
2957 @return EFI_DEVICE_ERROR The console device reported an error.
2962 IN INT32 Col OPTIONAL
,
2963 IN INT32 Row OPTIONAL
,
2964 IN CONST CHAR16
*Format
,
2970 if (Format
== NULL
) {
2971 return (EFI_INVALID_PARAMETER
);
2973 VA_START (Marker
, Format
);
2974 RetVal
= InternalShellPrintWorker(Col
, Row
, Format
, Marker
);
2980 Print at a specific location on the screen.
2982 This function will move the cursor to a given screen location and print the specified string.
2984 If -1 is specified for either the Row or Col the current screen location for BOTH
2987 If either Row or Col is out of range for the current console, then ASSERT.
2988 If Format is NULL, then ASSERT.
2990 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2991 the following additional flags:
2992 %N - Set output attribute to normal.
2993 %H - Set output attribute to highlight.
2994 %E - Set output attribute to error.
2995 %B - Set output attribute to blue color.
2996 %V - Set output attribute to green color.
2998 Note: The background color is controlled by the shell command cls.
3000 @param[in] Col The column to print at.
3001 @param[in] Row The row to print at.
3002 @param[in] Language The language of the string to retrieve. If this parameter
3003 is NULL, then the current platform language is used.
3004 @param[in] HiiFormatStringId The format string Id for getting from Hii.
3005 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
3006 @param[in] ... The variable argument list.
3008 @return EFI_SUCCESS The printing was successful.
3009 @return EFI_DEVICE_ERROR The console device reported an error.
3014 IN INT32 Col OPTIONAL
,
3015 IN INT32 Row OPTIONAL
,
3016 IN CONST CHAR8
*Language OPTIONAL
,
3017 IN CONST EFI_STRING_ID HiiFormatStringId
,
3018 IN CONST EFI_HII_HANDLE HiiFormatHandle
,
3023 CHAR16
*HiiFormatString
;
3026 RetVal
= EFI_DEVICE_ERROR
;
3028 VA_START (Marker
, HiiFormatHandle
);
3029 HiiFormatString
= HiiGetString(HiiFormatHandle
, HiiFormatStringId
, Language
);
3030 if (HiiFormatString
!= NULL
) {
3031 RetVal
= InternalShellPrintWorker (Col
, Row
, HiiFormatString
, Marker
);
3032 SHELL_FREE_NON_NULL (HiiFormatString
);
3040 Function to determine if a given filename represents a file or a directory.
3042 @param[in] DirName Path to directory to test.
3044 @retval EFI_SUCCESS The Path represents a directory
3045 @retval EFI_NOT_FOUND The Path does not represent a directory
3046 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
3047 @return The path failed to open
3052 IN CONST CHAR16
*DirName
3056 SHELL_FILE_HANDLE Handle
;
3057 CHAR16
*TempLocation
;
3058 CHAR16
*TempLocation2
;
3060 ASSERT(DirName
!= NULL
);
3063 TempLocation
= NULL
;
3065 Status
= ShellOpenFileByName(DirName
, &Handle
, EFI_FILE_MODE_READ
, 0);
3066 if (EFI_ERROR(Status
)) {
3068 // try good logic first.
3070 if (gEfiShellProtocol
!= NULL
) {
3071 TempLocation
= StrnCatGrow(&TempLocation
, NULL
, DirName
, 0);
3072 if (TempLocation
== NULL
) {
3073 ShellCloseFile(&Handle
);
3074 return (EFI_OUT_OF_RESOURCES
);
3076 TempLocation2
= StrStr(TempLocation
, L
":");
3077 if (TempLocation2
!= NULL
&& StrLen(StrStr(TempLocation
, L
":")) == 2) {
3078 *(TempLocation2
+1) = CHAR_NULL
;
3080 if (gEfiShellProtocol
->GetDevicePathFromMap(TempLocation
) != NULL
) {
3081 FreePool(TempLocation
);
3082 return (EFI_SUCCESS
);
3084 FreePool(TempLocation
);
3087 // probably a map name?!?!!?
3089 TempLocation
= StrStr(DirName
, L
"\\");
3090 if (TempLocation
!= NULL
&& *(TempLocation
+1) == CHAR_NULL
) {
3091 return (EFI_SUCCESS
);
3097 if (FileHandleIsDirectory(Handle
) == EFI_SUCCESS
) {
3098 ShellCloseFile(&Handle
);
3099 return (EFI_SUCCESS
);
3101 ShellCloseFile(&Handle
);
3102 return (EFI_NOT_FOUND
);
3106 Function to determine if a given filename represents a file.
3108 @param[in] Name Path to file to test.
3110 @retval EFI_SUCCESS The Path represents a file.
3111 @retval EFI_NOT_FOUND The Path does not represent a file.
3112 @retval other The path failed to open.
3117 IN CONST CHAR16
*Name
3121 SHELL_FILE_HANDLE Handle
;
3123 ASSERT(Name
!= NULL
);
3127 Status
= ShellOpenFileByName(Name
, &Handle
, EFI_FILE_MODE_READ
, 0);
3128 if (EFI_ERROR(Status
)) {
3132 if (FileHandleIsDirectory(Handle
) != EFI_SUCCESS
) {
3133 ShellCloseFile(&Handle
);
3134 return (EFI_SUCCESS
);
3136 ShellCloseFile(&Handle
);
3137 return (EFI_NOT_FOUND
);
3141 Function to determine if a given filename represents a file.
3143 This will search the CWD and then the Path.
3145 If Name is NULL, then ASSERT.
3147 @param[in] Name Path to file to test.
3149 @retval EFI_SUCCESS The Path represents a file.
3150 @retval EFI_NOT_FOUND The Path does not represent a file.
3151 @retval other The path failed to open.
3156 IN CONST CHAR16
*Name
3162 if (!EFI_ERROR(ShellIsFile(Name
))) {
3163 return (EFI_SUCCESS
);
3166 NewName
= ShellFindFilePath(Name
);
3167 if (NewName
== NULL
) {
3168 return (EFI_NOT_FOUND
);
3170 Status
= ShellIsFile(NewName
);
3176 Function return the number converted from a hex representation of a number.
3178 Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
3179 result. Use ShellConvertStringToUint64 instead.
3181 @param[in] String String representation of a number.
3183 @return The unsigned integer result of the conversion.
3184 @retval (UINTN)(-1) An error occured.
3189 IN CONST CHAR16
*String
3194 if (!EFI_ERROR(ShellConvertStringToUint64(String
, &RetVal
, TRUE
, TRUE
))) {
3195 return ((UINTN
)RetVal
);
3198 return ((UINTN
)(-1));
3202 Function to determine whether a string is decimal or hex representation of a number
3203 and return the number converted from the string. Spaces are always skipped.
3205 @param[in] String String representation of a number
3208 @retval (UINTN)(-1) An error ocurred.
3213 IN CONST CHAR16
*String
3221 if (!InternalShellIsHexOrDecimalNumber(String
, Hex
, TRUE
, FALSE
)) {
3225 if (!EFI_ERROR(ShellConvertStringToUint64(String
, &RetVal
, Hex
, TRUE
))) {
3226 return ((UINTN
)RetVal
);
3228 return ((UINTN
)(-1));
3232 Safely append with automatic string resizing given length of Destination and
3233 desired length of copy from Source.
3235 append the first D characters of Source to the end of Destination, where D is
3236 the lesser of Count and the StrLen() of Source. If appending those D characters
3237 will fit within Destination (whose Size is given as CurrentSize) and
3238 still leave room for a NULL terminator, then those characters are appended,
3239 starting at the original terminating NULL of Destination, and a new terminating
3242 If appending D characters onto Destination will result in a overflow of the size
3243 given in CurrentSize the string will be grown such that the copy can be performed
3244 and CurrentSize will be updated to the new size.
3246 If Source is NULL, there is nothing to append, just return the current buffer in
3249 if Destination is NULL, then ASSERT()
3250 if Destination's current length (including NULL terminator) is already more then
3251 CurrentSize, then ASSERT()
3253 @param[in, out] Destination The String to append onto
3254 @param[in, out] CurrentSize on call the number of bytes in Destination. On
3255 return possibly the new size (still in bytes). if NULL
3256 then allocate whatever is needed.
3257 @param[in] Source The String to append from
3258 @param[in] Count Maximum number of characters to append. if 0 then
3261 @return Destination return the resultant string.
3266 IN OUT CHAR16
**Destination
,
3267 IN OUT UINTN
*CurrentSize
,
3268 IN CONST CHAR16
*Source
,
3272 UINTN DestinationStartSize
;
3278 ASSERT(Destination
!= NULL
);
3281 // If there's nothing to do then just return Destination
3283 if (Source
== NULL
) {
3284 return (*Destination
);
3288 // allow for un-initialized pointers, based on size being 0
3290 if (CurrentSize
!= NULL
&& *CurrentSize
== 0) {
3291 *Destination
= NULL
;
3295 // allow for NULL pointers address as Destination
3297 if (*Destination
!= NULL
) {
3298 ASSERT(CurrentSize
!= 0);
3299 DestinationStartSize
= StrSize(*Destination
);
3300 ASSERT(DestinationStartSize
<= *CurrentSize
);
3302 DestinationStartSize
= 0;
3303 // ASSERT(*CurrentSize == 0);
3307 // Append all of Source?
3310 Count
= StrLen(Source
);
3314 // Test and grow if required
3316 if (CurrentSize
!= NULL
) {
3317 NewSize
= *CurrentSize
;
3318 if (NewSize
< DestinationStartSize
+ (Count
* sizeof(CHAR16
))) {
3319 while (NewSize
< (DestinationStartSize
+ (Count
*sizeof(CHAR16
)))) {
3320 NewSize
+= 2 * Count
* sizeof(CHAR16
);
3322 *Destination
= ReallocatePool(*CurrentSize
, NewSize
, *Destination
);
3323 *CurrentSize
= NewSize
;
3326 NewSize
= (Count
+1)*sizeof(CHAR16
);
3327 *Destination
= AllocateZeroPool(NewSize
);
3331 // Now use standard StrnCat on a big enough buffer
3333 if (*Destination
== NULL
) {
3337 StrnCatS(*Destination
, NewSize
/sizeof(CHAR16
), Source
, Count
);
3338 return *Destination
;
3342 Prompt the user and return the resultant answer to the requestor.
3344 This function will display the requested question on the shell prompt and then
3345 wait for an appropriate answer to be input from the console.
3347 if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
3348 or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
3350 if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
3353 In either case *Response must be callee freed if Response was not NULL;
3355 @param Type What type of question is asked. This is used to filter the input
3356 to prevent invalid answers to question.
3357 @param Prompt Pointer to string prompt to use to request input.
3358 @param Response Pointer to Response which will be populated upon return.
3360 @retval EFI_SUCCESS The operation was sucessful.
3361 @retval EFI_UNSUPPORTED The operation is not supported as requested.
3362 @retval EFI_INVALID_PARAMETER A parameter was invalid.
3363 @return other The operation failed.
3367 ShellPromptForResponse (
3368 IN SHELL_PROMPT_REQUEST_TYPE Type
,
3369 IN CHAR16
*Prompt OPTIONAL
,
3370 IN OUT VOID
**Response OPTIONAL
3376 SHELL_PROMPT_RESPONSE
*Resp
;
3380 Status
= EFI_UNSUPPORTED
;
3384 if (Type
!= ShellPromptResponseTypeFreeform
) {
3385 Resp
= (SHELL_PROMPT_RESPONSE
*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE
));
3387 if (Response
!= NULL
) {
3390 return (EFI_OUT_OF_RESOURCES
);
3395 case ShellPromptResponseTypeQuitContinue
:
3396 if (Prompt
!= NULL
) {
3397 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3400 // wait for valid response
3402 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3403 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3404 if (EFI_ERROR(Status
)) {
3407 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3408 if (Key
.UnicodeChar
== L
'Q' || Key
.UnicodeChar
==L
'q') {
3409 *Resp
= ShellPromptResponseQuit
;
3411 *Resp
= ShellPromptResponseContinue
;
3414 case ShellPromptResponseTypeYesNoCancel
:
3415 if (Prompt
!= NULL
) {
3416 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3419 // wait for valid response
3421 *Resp
= ShellPromptResponseMax
;
3422 while (*Resp
== ShellPromptResponseMax
) {
3423 if (ShellGetExecutionBreakFlag()) {
3424 Status
= EFI_ABORTED
;
3427 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3428 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3429 if (EFI_ERROR(Status
)) {
3432 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3433 switch (Key
.UnicodeChar
) {
3436 *Resp
= ShellPromptResponseYes
;
3440 *Resp
= ShellPromptResponseNo
;
3444 *Resp
= ShellPromptResponseCancel
;
3449 case ShellPromptResponseTypeYesNoAllCancel
:
3450 if (Prompt
!= NULL
) {
3451 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3454 // wait for valid response
3456 *Resp
= ShellPromptResponseMax
;
3457 while (*Resp
== ShellPromptResponseMax
) {
3458 if (ShellGetExecutionBreakFlag()) {
3459 Status
= EFI_ABORTED
;
3462 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3463 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3464 if (EFI_ERROR(Status
)) {
3468 if (Key
.UnicodeChar
<= 127 && Key
.UnicodeChar
>= 32) {
3469 ShellPrintEx (-1, -1, L
"%c", Key
.UnicodeChar
);
3472 switch (Key
.UnicodeChar
) {
3475 *Resp
= ShellPromptResponseYes
;
3479 *Resp
= ShellPromptResponseNo
;
3483 *Resp
= ShellPromptResponseAll
;
3487 *Resp
= ShellPromptResponseCancel
;
3492 case ShellPromptResponseTypeEnterContinue
:
3493 case ShellPromptResponseTypeAnyKeyContinue
:
3494 if (Prompt
!= NULL
) {
3495 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3498 // wait for valid response
3500 *Resp
= ShellPromptResponseMax
;
3501 while (*Resp
== ShellPromptResponseMax
) {
3502 if (ShellGetExecutionBreakFlag()) {
3503 Status
= EFI_ABORTED
;
3506 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3507 if (Type
== ShellPromptResponseTypeEnterContinue
) {
3508 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3509 if (EFI_ERROR(Status
)) {
3512 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3513 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3514 *Resp
= ShellPromptResponseContinue
;
3518 if (Type
== ShellPromptResponseTypeAnyKeyContinue
) {
3519 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3520 ASSERT_EFI_ERROR(Status
);
3521 *Resp
= ShellPromptResponseContinue
;
3526 case ShellPromptResponseTypeYesNo
:
3527 if (Prompt
!= NULL
) {
3528 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3531 // wait for valid response
3533 *Resp
= ShellPromptResponseMax
;
3534 while (*Resp
== ShellPromptResponseMax
) {
3535 if (ShellGetExecutionBreakFlag()) {
3536 Status
= EFI_ABORTED
;
3539 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3540 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3541 if (EFI_ERROR(Status
)) {
3544 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3545 switch (Key
.UnicodeChar
) {
3548 *Resp
= ShellPromptResponseYes
;
3552 *Resp
= ShellPromptResponseNo
;
3557 case ShellPromptResponseTypeFreeform
:
3558 if (Prompt
!= NULL
) {
3559 ShellPrintEx(-1, -1, L
"%s", Prompt
);
3562 if (ShellGetExecutionBreakFlag()) {
3563 Status
= EFI_ABORTED
;
3566 gBS
->WaitForEvent (1, &gST
->ConIn
->WaitForKey
, &EventIndex
);
3567 Status
= gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
);
3568 if (EFI_ERROR(Status
)) {
3571 ShellPrintEx(-1, -1, L
"%c", Key
.UnicodeChar
);
3572 if (Key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
3575 ASSERT((Buffer
== NULL
&& Size
== 0) || (Buffer
!= NULL
));
3576 StrnCatGrow(&Buffer
, &Size
, &Key
.UnicodeChar
, 1);
3580 // This is the location to add new prompt types.
3581 // If your new type loops remember to add ExecutionBreak support.
3587 if (Response
!= NULL
) {
3590 } else if (Buffer
!= NULL
) {
3599 if (Buffer
!= NULL
) {
3604 ShellPrintEx(-1, -1, L
"\r\n");
3609 Prompt the user and return the resultant answer to the requestor.
3611 This function is the same as ShellPromptForResponse, except that the prompt is
3612 automatically pulled from HII.
3614 @param Type What type of question is asked. This is used to filter the input
3615 to prevent invalid answers to question.
3616 @param[in] HiiFormatStringId The format string Id for getting from Hii.
3617 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
3618 @param Response Pointer to Response which will be populated upon return.
3620 @retval EFI_SUCCESS the operation was sucessful.
3621 @return other the operation failed.
3623 @sa ShellPromptForResponse
3627 ShellPromptForResponseHii (
3628 IN SHELL_PROMPT_REQUEST_TYPE Type
,
3629 IN CONST EFI_STRING_ID HiiFormatStringId
,
3630 IN CONST EFI_HII_HANDLE HiiFormatHandle
,
3631 IN OUT VOID
**Response
3637 Prompt
= HiiGetString(HiiFormatHandle
, HiiFormatStringId
, NULL
);
3638 Status
= ShellPromptForResponse(Type
, Prompt
, Response
);
3644 Function to determin if an entire string is a valid number.
3646 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
3648 @param[in] String The string to evaluate.
3649 @param[in] ForceHex TRUE - always assume hex.
3650 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
3651 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
3653 @retval TRUE It is all numeric (dec/hex) characters.
3654 @retval FALSE There is a non-numeric character.
3657 InternalShellIsHexOrDecimalNumber (
3658 IN CONST CHAR16
*String
,
3659 IN CONST BOOLEAN ForceHex
,
3660 IN CONST BOOLEAN StopAtSpace
,
3661 IN CONST BOOLEAN TimeNumbers
3665 BOOLEAN LeadingZero
;
3667 if (String
== NULL
) {
3672 // chop off a single negative sign
3674 if (*String
== L
'-') {
3678 if (*String
== CHAR_NULL
) {
3683 // chop leading zeroes
3685 LeadingZero
= FALSE
;
3686 while(*String
== L
'0'){
3691 // allow '0x' or '0X', but not 'x' or 'X'
3693 if (*String
== L
'x' || *String
== L
'X') {
3696 // we got an x without a preceeding 0
3702 } else if (ForceHex
) {
3709 // loop through the remaining characters and use the lib function
3711 for ( ; *String
!= CHAR_NULL
&& !(StopAtSpace
&& *String
== L
' ') ; String
++){
3712 if (TimeNumbers
&& (String
[0] == L
':')) {
3716 if (!ShellIsHexaDecimalDigitCharacter(*String
)) {
3720 if (!ShellIsDecimalDigitCharacter(*String
)) {
3730 Function to determine if a given filename exists.
3732 @param[in] Name Path to test.
3734 @retval EFI_SUCCESS The Path represents a file.
3735 @retval EFI_NOT_FOUND The Path does not represent a file.
3736 @retval other The path failed to open.
3741 IN CONST CHAR16
*Name
3745 EFI_SHELL_FILE_INFO
*List
;
3747 ASSERT(Name
!= NULL
);
3750 Status
= ShellOpenFileMetaArg((CHAR16
*)Name
, EFI_FILE_MODE_READ
, &List
);
3751 if (EFI_ERROR(Status
)) {
3755 ShellCloseFileMetaArg(&List
);
3757 return (EFI_SUCCESS
);
3761 Convert a Unicode character to numerical value.
3763 This internal function only deal with Unicode character
3764 which maps to a valid hexadecimal ASII character, i.e.
3765 L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
3766 Unicode character, the value returned does not make sense.
3768 @param Char The character to convert.
3770 @return The numerical value converted.
3774 InternalShellHexCharToUintn (
3778 if (ShellIsDecimalDigitCharacter (Char
)) {
3782 return (10 + CharToUpper (Char
) - L
'A');
3786 Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
3788 This function returns a value of type UINT64 by interpreting the contents
3789 of the Unicode string specified by String as a hexadecimal number.
3790 The format of the input Unicode string String is:
3792 [spaces][zeros][x][hexadecimal digits].
3794 The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
3795 The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
3796 If "x" appears in the input string, it must be prefixed with at least one 0.
3797 The function will ignore the pad space, which includes spaces or tab characters,
3798 before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
3799 [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
3800 first valid hexadecimal digit. Then, the function stops at the first character that is
3801 a not a valid hexadecimal character or NULL, whichever one comes first.
3803 If String has only pad spaces, then zero is returned.
3804 If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
3805 then zero is returned.
3807 @param[in] String A pointer to a Null-terminated Unicode string.
3808 @param[out] Value Upon a successful return the value of the conversion.
3809 @param[in] StopAtSpace FALSE to skip spaces.
3811 @retval EFI_SUCCESS The conversion was successful.
3812 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3813 @retval EFI_DEVICE_ERROR An overflow occured.
3816 InternalShellStrHexToUint64 (
3817 IN CONST CHAR16
*String
,
3819 IN CONST BOOLEAN StopAtSpace
3824 if (String
== NULL
|| StrSize(String
) == 0 || Value
== NULL
) {
3825 return (EFI_INVALID_PARAMETER
);
3829 // Ignore the pad spaces (space or tab)
3831 while ((*String
== L
' ') || (*String
== L
'\t')) {
3836 // Ignore leading Zeros after the spaces
3838 while (*String
== L
'0') {
3842 if (CharToUpper (*String
) == L
'X') {
3843 if (*(String
- 1) != L
'0') {
3855 // there is a space where there should't be
3857 if (*String
== L
' ') {
3858 return (EFI_INVALID_PARAMETER
);
3861 while (ShellIsHexaDecimalDigitCharacter (*String
)) {
3863 // If the Hex Number represented by String overflows according
3864 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3866 if (!(Result
<= (RShiftU64((((UINT64
) ~0) - InternalShellHexCharToUintn (*String
)), 4)))) {
3867 // if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
3868 return (EFI_DEVICE_ERROR
);
3871 Result
= (LShiftU64(Result
, 4));
3872 Result
+= InternalShellHexCharToUintn (*String
);
3876 // stop at spaces if requested
3878 if (StopAtSpace
&& *String
== L
' ') {
3884 return (EFI_SUCCESS
);
3888 Convert a Null-terminated Unicode decimal string to a value of
3891 This function returns a value of type UINT64 by interpreting the contents
3892 of the Unicode string specified by String as a decimal number. The format
3893 of the input Unicode string String is:
3895 [spaces] [decimal digits].
3897 The valid decimal digit character is in the range [0-9]. The
3898 function will ignore the pad space, which includes spaces or
3899 tab characters, before [decimal digits]. The running zero in the
3900 beginning of [decimal digits] will be ignored. Then, the function
3901 stops at the first character that is a not a valid decimal character
3902 or a Null-terminator, whichever one comes first.
3904 If String has only pad spaces, then 0 is returned.
3905 If String has no pad spaces or valid decimal digits,
3908 @param[in] String A pointer to a Null-terminated Unicode string.
3909 @param[out] Value Upon a successful return the value of the conversion.
3910 @param[in] StopAtSpace FALSE to skip spaces.
3912 @retval EFI_SUCCESS The conversion was successful.
3913 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3914 @retval EFI_DEVICE_ERROR An overflow occured.
3917 InternalShellStrDecimalToUint64 (
3918 IN CONST CHAR16
*String
,
3920 IN CONST BOOLEAN StopAtSpace
3925 if (String
== NULL
|| StrSize (String
) == 0 || Value
== NULL
) {
3926 return (EFI_INVALID_PARAMETER
);
3930 // Ignore the pad spaces (space or tab)
3932 while ((*String
== L
' ') || (*String
== L
'\t')) {
3937 // Ignore leading Zeros after the spaces
3939 while (*String
== L
'0') {
3946 // Stop upon space if requested
3947 // (if the whole value was 0)
3949 if (StopAtSpace
&& *String
== L
' ') {
3951 return (EFI_SUCCESS
);
3954 while (ShellIsDecimalDigitCharacter (*String
)) {
3956 // If the number represented by String overflows according
3957 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3960 if (!(Result
<= (DivU64x32((((UINT64
) ~0) - (*String
- L
'0')),10)))) {
3961 return (EFI_DEVICE_ERROR
);
3964 Result
= MultU64x32(Result
, 10) + (*String
- L
'0');
3968 // Stop at spaces if requested
3970 if (StopAtSpace
&& *String
== L
' ') {
3977 return (EFI_SUCCESS
);
3981 Function to verify and convert a string to its numerical value.
3983 If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
3985 @param[in] String The string to evaluate.
3986 @param[out] Value Upon a successful return the value of the conversion.
3987 @param[in] ForceHex TRUE - always assume hex.
3988 @param[in] StopAtSpace FALSE to skip spaces.
3990 @retval EFI_SUCCESS The conversion was successful.
3991 @retval EFI_INVALID_PARAMETER String contained an invalid character.
3992 @retval EFI_NOT_FOUND String was a number, but Value was NULL.
3996 ShellConvertStringToUint64(
3997 IN CONST CHAR16
*String
,
3999 IN CONST BOOLEAN ForceHex
,
4000 IN CONST BOOLEAN StopAtSpace
4004 CONST CHAR16
*Walker
;
4010 if (!InternalShellIsHexOrDecimalNumber(String
, Hex
, StopAtSpace
, FALSE
)) {
4013 if (!InternalShellIsHexOrDecimalNumber(String
, Hex
, StopAtSpace
, FALSE
)) {
4014 return (EFI_INVALID_PARAMETER
);
4017 return (EFI_INVALID_PARAMETER
);
4022 // Chop off leading spaces
4024 for (Walker
= String
; Walker
!= NULL
&& *Walker
!= CHAR_NULL
&& *Walker
== L
' '; Walker
++);
4027 // make sure we have something left that is numeric.
4029 if (Walker
== NULL
|| *Walker
== CHAR_NULL
|| !InternalShellIsHexOrDecimalNumber(Walker
, Hex
, StopAtSpace
, FALSE
)) {
4030 return (EFI_INVALID_PARAMETER
);
4034 // do the conversion.
4036 if (Hex
|| StrnCmp(Walker
, L
"0x", 2) == 0 || StrnCmp(Walker
, L
"0X", 2) == 0){
4037 Status
= InternalShellStrHexToUint64(Walker
, &RetVal
, StopAtSpace
);
4039 Status
= InternalShellStrDecimalToUint64(Walker
, &RetVal
, StopAtSpace
);
4042 if (Value
== NULL
&& !EFI_ERROR(Status
)) {
4043 return (EFI_NOT_FOUND
);
4046 if (Value
!= NULL
) {
4054 Function to determin if an entire string is a valid number.
4056 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
4058 @param[in] String The string to evaluate.
4059 @param[in] ForceHex TRUE - always assume hex.
4060 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
4062 @retval TRUE It is all numeric (dec/hex) characters.
4063 @retval FALSE There is a non-numeric character.
4067 ShellIsHexOrDecimalNumber (
4068 IN CONST CHAR16
*String
,
4069 IN CONST BOOLEAN ForceHex
,
4070 IN CONST BOOLEAN StopAtSpace
4073 if (ShellConvertStringToUint64(String
, NULL
, ForceHex
, StopAtSpace
) == EFI_NOT_FOUND
) {
4080 Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
4081 buffer. The returned buffer must be callee freed.
4083 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4084 maintained and not changed for all operations with the same file.
4086 @param[in] Handle SHELL_FILE_HANDLE to read from.
4087 @param[in, out] Ascii Boolean value for indicating whether the file is
4088 Ascii (TRUE) or UCS2 (FALSE).
4090 @return The line of text from the file.
4091 @retval NULL There was not enough memory available.
4093 @sa ShellFileHandleReadLine
4097 ShellFileHandleReturnLine(
4098 IN SHELL_FILE_HANDLE Handle
,
4099 IN OUT BOOLEAN
*Ascii
4109 Status
= ShellFileHandleReadLine(Handle
, RetVal
, &Size
, FALSE
, Ascii
);
4110 if (Status
== EFI_BUFFER_TOO_SMALL
) {
4111 RetVal
= AllocateZeroPool(Size
);
4112 if (RetVal
== NULL
) {
4115 Status
= ShellFileHandleReadLine(Handle
, RetVal
, &Size
, FALSE
, Ascii
);
4118 if (Status
== EFI_END_OF_FILE
&& RetVal
!= NULL
&& *RetVal
!= CHAR_NULL
) {
4119 Status
= EFI_SUCCESS
;
4121 if (EFI_ERROR(Status
) && (RetVal
!= NULL
)) {
4129 Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
4131 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4132 maintained and not changed for all operations with the same file.
4134 NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ
4137 @param[in] Handle SHELL_FILE_HANDLE to read from.
4138 @param[in, out] Buffer The pointer to buffer to read into. If this function
4139 returns EFI_SUCCESS, then on output Buffer will
4140 contain a UCS2 string, even if the file being
4142 @param[in, out] Size On input, pointer to number of bytes in Buffer.
4143 On output, unchanged unless Buffer is too small
4144 to contain the next line of the file. In that
4145 case Size is set to the number of bytes needed
4146 to hold the next line of the file (as a UCS2
4147 string, even if it is an ASCII file).
4148 @param[in] Truncate If the buffer is large enough, this has no effect.
4149 If the buffer is is too small and Truncate is TRUE,
4150 the line will be truncated.
4151 If the buffer is is too small and Truncate is FALSE,
4152 then no read will occur.
4154 @param[in, out] Ascii Boolean value for indicating whether the file is
4155 Ascii (TRUE) or UCS2 (FALSE).
4157 @retval EFI_SUCCESS The operation was successful. The line is stored in
4159 @retval EFI_END_OF_FILE There are no more lines in the file.
4160 @retval EFI_INVALID_PARAMETER Handle was NULL.
4161 @retval EFI_INVALID_PARAMETER Size was NULL.
4162 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
4163 Size was updated to the minimum space required.
4167 ShellFileHandleReadLine(
4168 IN SHELL_FILE_HANDLE Handle
,
4169 IN OUT CHAR16
*Buffer
,
4171 IN BOOLEAN Truncate
,
4172 IN OUT BOOLEAN
*Ascii
4179 UINT64 OriginalFilePosition
;
4185 return (EFI_INVALID_PARAMETER
);
4187 if (Buffer
== NULL
) {
4190 *Buffer
= CHAR_NULL
;
4192 gEfiShellProtocol
->GetFilePosition(Handle
, &OriginalFilePosition
);
4193 if (OriginalFilePosition
== 0) {
4194 CharSize
= sizeof(CHAR16
);
4195 Status
= gEfiShellProtocol
->ReadFile(Handle
, &CharSize
, &CharBuffer
);
4196 ASSERT_EFI_ERROR(Status
);
4197 if (CharBuffer
== gUnicodeFileTag
) {
4201 gEfiShellProtocol
->SetFilePosition(Handle
, OriginalFilePosition
);
4206 CharSize
= sizeof(CHAR8
);
4208 CharSize
= sizeof(CHAR16
);
4210 for (CountSoFar
= 0;;CountSoFar
++){
4212 Status
= gEfiShellProtocol
->ReadFile(Handle
, &CharSize
, &CharBuffer
);
4213 if ( EFI_ERROR(Status
)
4215 || (CharBuffer
== L
'\n' && !(*Ascii
))
4216 || (CharBuffer
== '\n' && *Ascii
)
4218 if (CharSize
== 0) {
4219 Status
= EFI_END_OF_FILE
;
4224 // if we have space save it...
4226 if ((CountSoFar
+1)*sizeof(CHAR16
) < *Size
){
4227 ASSERT(Buffer
!= NULL
);
4228 ((CHAR16
*)Buffer
)[CountSoFar
] = CharBuffer
;
4229 ((CHAR16
*)Buffer
)[CountSoFar
+1] = CHAR_NULL
;
4234 // if we ran out of space tell when...
4236 if ((CountSoFar
+1)*sizeof(CHAR16
) > *Size
){
4237 *Size
= (CountSoFar
+1)*sizeof(CHAR16
);
4239 gEfiShellProtocol
->SetFilePosition(Handle
, OriginalFilePosition
);
4241 DEBUG((DEBUG_WARN
, "The line was truncated in ShellFileHandleReadLine"));
4243 return (EFI_BUFFER_TOO_SMALL
);
4245 while(Buffer
[StrLen(Buffer
)-1] == L
'\r') {
4246 Buffer
[StrLen(Buffer
)-1] = CHAR_NULL
;
4253 Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
4255 @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
4256 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
4257 @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
4258 the help content only.
4259 @retval EFI_DEVICE_ERROR The help data format was incorrect.
4260 @retval EFI_NOT_FOUND The help data could not be found.
4261 @retval EFI_SUCCESS The operation was successful.
4266 IN CONST CHAR16
*CommandToGetHelpOn
,
4267 IN CONST CHAR16
*SectionToGetHelpOn
,
4268 IN BOOLEAN PrintCommandText
4277 // Get the string to print based
4279 Status
= gEfiShellProtocol
->GetHelpText (CommandToGetHelpOn
, SectionToGetHelpOn
, &OutText
);
4282 // make sure we got a valid string
4284 if (EFI_ERROR(Status
)){
4287 if (OutText
== NULL
|| StrLen(OutText
) == 0) {
4288 return EFI_NOT_FOUND
;
4292 // Chop off trailing stuff we dont need
4294 while (OutText
[StrLen(OutText
)-1] == L
'\r' || OutText
[StrLen(OutText
)-1] == L
'\n' || OutText
[StrLen(OutText
)-1] == L
' ') {
4295 OutText
[StrLen(OutText
)-1] = CHAR_NULL
;
4299 // Print this out to the console
4301 if (PrintCommandText
) {
4302 ShellPrintEx(-1, -1, L
"%H%-14s%N- %s\r\n", CommandToGetHelpOn
, OutText
);
4304 ShellPrintEx(-1, -1, L
"%N%s\r\n", OutText
);
4307 SHELL_FREE_NON_NULL(OutText
);
4313 Function to delete a file by name
4315 @param[in] FileName Pointer to file name to delete.
4317 @retval EFI_SUCCESS the file was deleted sucessfully
4318 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
4320 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
4321 @retval EFI_NOT_FOUND The specified file could not be found on the
4322 device or the file system could not be found
4324 @retval EFI_NO_MEDIA The device has no medium.
4325 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
4326 medium is no longer supported.
4327 @retval EFI_DEVICE_ERROR The device reported an error.
4328 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
4329 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
4330 @retval EFI_ACCESS_DENIED The file was opened read only.
4331 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
4333 @retval other The file failed to open
4337 ShellDeleteFileByName(
4338 IN CONST CHAR16
*FileName
4342 SHELL_FILE_HANDLE FileHandle
;
4344 Status
= ShellFileExists(FileName
);
4346 if (Status
== EFI_SUCCESS
){
4347 Status
= ShellOpenFileByName(FileName
, &FileHandle
, EFI_FILE_MODE_READ
| EFI_FILE_MODE_WRITE
| EFI_FILE_MODE_CREATE
, 0x0);
4348 if (Status
== EFI_SUCCESS
){
4349 Status
= ShellDeleteFile(&FileHandle
);
4358 Cleans off all the quotes in the string.
4360 @param[in] OriginalString pointer to the string to be cleaned.
4361 @param[out] CleanString The new string with all quotes removed.
4362 Memory allocated in the function and free
4365 @retval EFI_SUCCESS The operation was successful.
4368 InternalShellStripQuotes (
4369 IN CONST CHAR16
*OriginalString
,
4370 OUT CHAR16
**CleanString
4375 if (OriginalString
== NULL
|| CleanString
== NULL
) {
4376 return EFI_INVALID_PARAMETER
;
4379 *CleanString
= AllocateCopyPool (StrSize (OriginalString
), OriginalString
);
4380 if (*CleanString
== NULL
) {
4381 return EFI_OUT_OF_RESOURCES
;
4384 for (Walker
= *CleanString
; Walker
!= NULL
&& *Walker
!= CHAR_NULL
; Walker
++) {
4385 if (*Walker
== L
'\"') {
4386 CopyMem(Walker
, Walker
+1, StrSize(Walker
) - sizeof(Walker
[0]));