]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLib/UefiShellLib.c
Merge branch 'master' of https://github.com/tianocore/edk2
[mirror_edk2.git] / ShellPkg / Library / UefiShellLib / UefiShellLib.c
1 /** @file
2 Provides interface to shell functionality for shell commands and applications.
3
4 Copyright 2016 Dell Inc.
5 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "UefiShellLib.h"
17 #include <ShellBase.h>
18 #include <Library/SortLib.h>
19 #include <Library/BaseLib.h>
20
21 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)
22
23 //
24 // globals...
25 //
26 SHELL_PARAM_ITEM EmptyParamList[] = {
27 {NULL, TypeMax}
28 };
29 SHELL_PARAM_ITEM SfoParamList[] = {
30 {L"-sfo", TypeFlag},
31 {NULL, TypeMax}
32 };
33 EFI_SHELL_ENVIRONMENT2 *mEfiShellEnvironment2;
34 EFI_SHELL_INTERFACE *mEfiShellInterface;
35 EFI_SHELL_PROTOCOL *gEfiShellProtocol;
36 EFI_SHELL_PARAMETERS_PROTOCOL *gEfiShellParametersProtocol;
37 EFI_HANDLE mEfiShellEnvironment2Handle;
38 FILE_HANDLE_FUNCTION_MAP FileFunctionMap;
39
40 /**
41 Check if a Unicode character is a hexadecimal character.
42
43 This internal function checks if a Unicode character is a
44 numeric character. The valid hexadecimal characters are
45 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
46
47 @param Char The character to check against.
48
49 @retval TRUE If the Char is a hexadecmial character.
50 @retval FALSE If the Char is not a hexadecmial character.
51
52 **/
53 BOOLEAN
54 EFIAPI
55 ShellIsHexaDecimalDigitCharacter (
56 IN CHAR16 Char
57 )
58 {
59 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
60 }
61
62 /**
63 Check if a Unicode character is a decimal character.
64
65 This internal function checks if a Unicode character is a
66 decimal character. The valid characters are
67 L'0' to L'9'.
68
69
70 @param Char The character to check against.
71
72 @retval TRUE If the Char is a hexadecmial character.
73 @retval FALSE If the Char is not a hexadecmial character.
74
75 **/
76 BOOLEAN
77 EFIAPI
78 ShellIsDecimalDigitCharacter (
79 IN CHAR16 Char
80 )
81 {
82 return (BOOLEAN) (Char >= L'0' && Char <= L'9');
83 }
84
85 /**
86 Helper function to find ShellEnvironment2 for constructor.
87
88 @param[in] ImageHandle A copy of the calling image's handle.
89
90 @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
91 **/
92 EFI_STATUS
93 EFIAPI
94 ShellFindSE2 (
95 IN EFI_HANDLE ImageHandle
96 )
97 {
98 EFI_STATUS Status;
99 EFI_HANDLE *Buffer;
100 UINTN BufferSize;
101 UINTN HandleIndex;
102
103 BufferSize = 0;
104 Buffer = NULL;
105 Status = gBS->OpenProtocol(ImageHandle,
106 &gEfiShellEnvironment2Guid,
107 (VOID **)&mEfiShellEnvironment2,
108 ImageHandle,
109 NULL,
110 EFI_OPEN_PROTOCOL_GET_PROTOCOL
111 );
112 //
113 // look for the mEfiShellEnvironment2 protocol at a higher level
114 //
115 if (EFI_ERROR (Status) || !(CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid))){
116 //
117 // figure out how big of a buffer we need.
118 //
119 Status = gBS->LocateHandle (ByProtocol,
120 &gEfiShellEnvironment2Guid,
121 NULL, // ignored for ByProtocol
122 &BufferSize,
123 Buffer
124 );
125 //
126 // maybe it's not there???
127 //
128 if (Status == EFI_BUFFER_TOO_SMALL) {
129 Buffer = (EFI_HANDLE*)AllocateZeroPool(BufferSize);
130 if (Buffer == NULL) {
131 return (EFI_OUT_OF_RESOURCES);
132 }
133 Status = gBS->LocateHandle (ByProtocol,
134 &gEfiShellEnvironment2Guid,
135 NULL, // ignored for ByProtocol
136 &BufferSize,
137 Buffer
138 );
139 }
140 if (!EFI_ERROR (Status) && Buffer != NULL) {
141 //
142 // now parse the list of returned handles
143 //
144 Status = EFI_NOT_FOUND;
145 for (HandleIndex = 0; HandleIndex < (BufferSize/sizeof(Buffer[0])); HandleIndex++) {
146 Status = gBS->OpenProtocol(Buffer[HandleIndex],
147 &gEfiShellEnvironment2Guid,
148 (VOID **)&mEfiShellEnvironment2,
149 ImageHandle,
150 NULL,
151 EFI_OPEN_PROTOCOL_GET_PROTOCOL
152 );
153 if (CompareGuid (&mEfiShellEnvironment2->SESGuid, &gEfiShellEnvironment2ExtGuid)) {
154 mEfiShellEnvironment2Handle = Buffer[HandleIndex];
155 Status = EFI_SUCCESS;
156 break;
157 }
158 }
159 }
160 }
161 if (Buffer != NULL) {
162 FreePool (Buffer);
163 }
164 return (Status);
165 }
166
167 /**
168 Function to do most of the work of the constructor. Allows for calling
169 multiple times without complete re-initialization.
170
171 @param[in] ImageHandle A copy of the ImageHandle.
172 @param[in] SystemTable A pointer to the SystemTable for the application.
173
174 @retval EFI_SUCCESS The operationw as successful.
175 **/
176 EFI_STATUS
177 EFIAPI
178 ShellLibConstructorWorker (
179 IN EFI_HANDLE ImageHandle,
180 IN EFI_SYSTEM_TABLE *SystemTable
181 )
182 {
183 EFI_STATUS Status;
184
185 //
186 // UEFI 2.0 shell interfaces (used preferentially)
187 //
188 Status = gBS->OpenProtocol(
189 ImageHandle,
190 &gEfiShellProtocolGuid,
191 (VOID **)&gEfiShellProtocol,
192 ImageHandle,
193 NULL,
194 EFI_OPEN_PROTOCOL_GET_PROTOCOL
195 );
196 if (EFI_ERROR(Status)) {
197 //
198 // Search for the shell protocol
199 //
200 Status = gBS->LocateProtocol(
201 &gEfiShellProtocolGuid,
202 NULL,
203 (VOID **)&gEfiShellProtocol
204 );
205 if (EFI_ERROR(Status)) {
206 gEfiShellProtocol = NULL;
207 }
208 }
209 Status = gBS->OpenProtocol(
210 ImageHandle,
211 &gEfiShellParametersProtocolGuid,
212 (VOID **)&gEfiShellParametersProtocol,
213 ImageHandle,
214 NULL,
215 EFI_OPEN_PROTOCOL_GET_PROTOCOL
216 );
217 if (EFI_ERROR(Status)) {
218 gEfiShellParametersProtocol = NULL;
219 }
220
221 if (gEfiShellParametersProtocol == NULL || gEfiShellProtocol == NULL) {
222 //
223 // Moved to seperate function due to complexity
224 //
225 Status = ShellFindSE2(ImageHandle);
226
227 if (EFI_ERROR(Status)) {
228 DEBUG((DEBUG_ERROR, "Status: 0x%08x\r\n", Status));
229 mEfiShellEnvironment2 = NULL;
230 }
231 Status = gBS->OpenProtocol(ImageHandle,
232 &gEfiShellInterfaceGuid,
233 (VOID **)&mEfiShellInterface,
234 ImageHandle,
235 NULL,
236 EFI_OPEN_PROTOCOL_GET_PROTOCOL
237 );
238 if (EFI_ERROR(Status)) {
239 mEfiShellInterface = NULL;
240 }
241 }
242
243 //
244 // only success getting 2 of either the old or new, but no 1/2 and 1/2
245 //
246 if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface != NULL) ||
247 (gEfiShellProtocol != NULL && gEfiShellParametersProtocol != NULL) ) {
248 if (gEfiShellProtocol != NULL) {
249 FileFunctionMap.GetFileInfo = gEfiShellProtocol->GetFileInfo;
250 FileFunctionMap.SetFileInfo = gEfiShellProtocol->SetFileInfo;
251 FileFunctionMap.ReadFile = gEfiShellProtocol->ReadFile;
252 FileFunctionMap.WriteFile = gEfiShellProtocol->WriteFile;
253 FileFunctionMap.CloseFile = gEfiShellProtocol->CloseFile;
254 FileFunctionMap.DeleteFile = gEfiShellProtocol->DeleteFile;
255 FileFunctionMap.GetFilePosition = gEfiShellProtocol->GetFilePosition;
256 FileFunctionMap.SetFilePosition = gEfiShellProtocol->SetFilePosition;
257 FileFunctionMap.FlushFile = gEfiShellProtocol->FlushFile;
258 FileFunctionMap.GetFileSize = gEfiShellProtocol->GetFileSize;
259 } else {
260 FileFunctionMap.GetFileInfo = (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo;
261 FileFunctionMap.SetFileInfo = (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo;
262 FileFunctionMap.ReadFile = (EFI_SHELL_READ_FILE)FileHandleRead;
263 FileFunctionMap.WriteFile = (EFI_SHELL_WRITE_FILE)FileHandleWrite;
264 FileFunctionMap.CloseFile = (EFI_SHELL_CLOSE_FILE)FileHandleClose;
265 FileFunctionMap.DeleteFile = (EFI_SHELL_DELETE_FILE)FileHandleDelete;
266 FileFunctionMap.GetFilePosition = (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition;
267 FileFunctionMap.SetFilePosition = (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition;
268 FileFunctionMap.FlushFile = (EFI_SHELL_FLUSH_FILE)FileHandleFlush;
269 FileFunctionMap.GetFileSize = (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize;
270 }
271 return (EFI_SUCCESS);
272 }
273 return (EFI_NOT_FOUND);
274 }
275 /**
276 Constructor for the Shell library.
277
278 Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.
279
280 @param ImageHandle the image handle of the process
281 @param SystemTable the EFI System Table pointer
282
283 @retval EFI_SUCCESS the initialization was complete sucessfully
284 @return others an error ocurred during initialization
285 **/
286 EFI_STATUS
287 EFIAPI
288 ShellLibConstructor (
289 IN EFI_HANDLE ImageHandle,
290 IN EFI_SYSTEM_TABLE *SystemTable
291 )
292 {
293 mEfiShellEnvironment2 = NULL;
294 gEfiShellProtocol = NULL;
295 gEfiShellParametersProtocol = NULL;
296 mEfiShellInterface = NULL;
297 mEfiShellEnvironment2Handle = NULL;
298
299 //
300 // verify that auto initialize is not set false
301 //
302 if (PcdGetBool(PcdShellLibAutoInitialize) == 0) {
303 return (EFI_SUCCESS);
304 }
305
306 return (ShellLibConstructorWorker(ImageHandle, SystemTable));
307 }
308
309 /**
310 Destructor for the library. free any resources.
311
312 @param[in] ImageHandle A copy of the ImageHandle.
313 @param[in] SystemTable A pointer to the SystemTable for the application.
314
315 @retval EFI_SUCCESS The operation was successful.
316 @return An error from the CloseProtocol function.
317 **/
318 EFI_STATUS
319 EFIAPI
320 ShellLibDestructor (
321 IN EFI_HANDLE ImageHandle,
322 IN EFI_SYSTEM_TABLE *SystemTable
323 )
324 {
325 if (mEfiShellEnvironment2 != NULL) {
326 gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,
327 &gEfiShellEnvironment2Guid,
328 ImageHandle,
329 NULL);
330 mEfiShellEnvironment2 = NULL;
331 }
332 if (mEfiShellInterface != NULL) {
333 gBS->CloseProtocol(ImageHandle,
334 &gEfiShellInterfaceGuid,
335 ImageHandle,
336 NULL);
337 mEfiShellInterface = NULL;
338 }
339 if (gEfiShellProtocol != NULL) {
340 gBS->CloseProtocol(ImageHandle,
341 &gEfiShellProtocolGuid,
342 ImageHandle,
343 NULL);
344 gEfiShellProtocol = NULL;
345 }
346 if (gEfiShellParametersProtocol != NULL) {
347 gBS->CloseProtocol(ImageHandle,
348 &gEfiShellParametersProtocolGuid,
349 ImageHandle,
350 NULL);
351 gEfiShellParametersProtocol = NULL;
352 }
353 mEfiShellEnvironment2Handle = NULL;
354
355 return (EFI_SUCCESS);
356 }
357
358 /**
359 This function causes the shell library to initialize itself. If the shell library
360 is already initialized it will de-initialize all the current protocol poitners and
361 re-populate them again.
362
363 When the library is used with PcdShellLibAutoInitialize set to true this function
364 will return EFI_SUCCESS and perform no actions.
365
366 This function is intended for internal access for shell commands only.
367
368 @retval EFI_SUCCESS the initialization was complete sucessfully
369
370 **/
371 EFI_STATUS
372 EFIAPI
373 ShellInitialize (
374 )
375 {
376 //
377 // if auto initialize is not false then skip
378 //
379 if (PcdGetBool(PcdShellLibAutoInitialize) != 0) {
380 return (EFI_SUCCESS);
381 }
382
383 //
384 // deinit the current stuff
385 //
386 ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST));
387
388 //
389 // init the new stuff
390 //
391 return (ShellLibConstructorWorker(gImageHandle, gST));
392 }
393
394 /**
395 This function will retrieve the information about the file for the handle
396 specified and store it in allocated pool memory.
397
398 This function allocates a buffer to store the file's information. It is the
399 caller's responsibility to free the buffer
400
401 @param FileHandle The file handle of the file for which information is
402 being requested.
403
404 @retval NULL information could not be retrieved.
405
406 @return the information about the file
407 **/
408 EFI_FILE_INFO*
409 EFIAPI
410 ShellGetFileInfo (
411 IN SHELL_FILE_HANDLE FileHandle
412 )
413 {
414 return (FileFunctionMap.GetFileInfo(FileHandle));
415 }
416
417 /**
418 This function sets the information about the file for the opened handle
419 specified.
420
421 @param[in] FileHandle The file handle of the file for which information
422 is being set.
423
424 @param[in] FileInfo The information to set.
425
426 @retval EFI_SUCCESS The information was set.
427 @retval EFI_INVALID_PARAMETER A parameter was out of range or invalid.
428 @retval EFI_UNSUPPORTED The FileHandle does not support FileInfo.
429 @retval EFI_NO_MEDIA The device has no medium.
430 @retval EFI_DEVICE_ERROR The device reported an error.
431 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
432 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
433 @retval EFI_ACCESS_DENIED The file was opened read only.
434 @retval EFI_VOLUME_FULL The volume is full.
435 **/
436 EFI_STATUS
437 EFIAPI
438 ShellSetFileInfo (
439 IN SHELL_FILE_HANDLE FileHandle,
440 IN EFI_FILE_INFO *FileInfo
441 )
442 {
443 return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo));
444 }
445
446 /**
447 This function will open a file or directory referenced by DevicePath.
448
449 This function opens a file with the open mode according to the file path. The
450 Attributes is valid only for EFI_FILE_MODE_CREATE.
451
452 @param FilePath on input the device path to the file. On output
453 the remaining device path.
454 @param DeviceHandle pointer to the system device handle.
455 @param FileHandle pointer to the file handle.
456 @param OpenMode the mode to open the file with.
457 @param Attributes the file's file attributes.
458
459 @retval EFI_SUCCESS The information was set.
460 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
461 @retval EFI_UNSUPPORTED Could not open the file path.
462 @retval EFI_NOT_FOUND The specified file could not be found on the
463 device or the file system could not be found on
464 the device.
465 @retval EFI_NO_MEDIA The device has no medium.
466 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
467 medium is no longer supported.
468 @retval EFI_DEVICE_ERROR The device reported an error.
469 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
470 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
471 @retval EFI_ACCESS_DENIED The file was opened read only.
472 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
473 file.
474 @retval EFI_VOLUME_FULL The volume is full.
475 **/
476 EFI_STATUS
477 EFIAPI
478 ShellOpenFileByDevicePath(
479 IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
480 OUT EFI_HANDLE *DeviceHandle,
481 OUT SHELL_FILE_HANDLE *FileHandle,
482 IN UINT64 OpenMode,
483 IN UINT64 Attributes
484 )
485 {
486 CHAR16 *FileName;
487 EFI_STATUS Status;
488 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
489 EFI_FILE_PROTOCOL *Handle1;
490 EFI_FILE_PROTOCOL *Handle2;
491 CHAR16 *FnafPathName;
492 UINTN PathLen;
493
494 if (FilePath == NULL || FileHandle == NULL || DeviceHandle == NULL) {
495 return (EFI_INVALID_PARAMETER);
496 }
497
498 //
499 // which shell interface should we use
500 //
501 if (gEfiShellProtocol != NULL) {
502 //
503 // use UEFI Shell 2.0 method.
504 //
505 FileName = gEfiShellProtocol->GetFilePathFromDevicePath(*FilePath);
506 if (FileName == NULL) {
507 return (EFI_INVALID_PARAMETER);
508 }
509 Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes);
510 FreePool(FileName);
511 return (Status);
512 }
513
514
515 //
516 // use old shell method.
517 //
518 Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
519 FilePath,
520 DeviceHandle);
521 if (EFI_ERROR (Status)) {
522 return Status;
523 }
524 Status = gBS->OpenProtocol(*DeviceHandle,
525 &gEfiSimpleFileSystemProtocolGuid,
526 (VOID**)&EfiSimpleFileSystemProtocol,
527 gImageHandle,
528 NULL,
529 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
530 if (EFI_ERROR (Status)) {
531 return Status;
532 }
533 Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
534 if (EFI_ERROR (Status)) {
535 FileHandle = NULL;
536 return Status;
537 }
538
539 //
540 // go down directories one node at a time.
541 //
542 while (!IsDevicePathEnd (*FilePath)) {
543 //
544 // For file system access each node should be a file path component
545 //
546 if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
547 DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
548 ) {
549 FileHandle = NULL;
550 return (EFI_INVALID_PARAMETER);
551 }
552 //
553 // Open this file path node
554 //
555 Handle2 = Handle1;
556 Handle1 = NULL;
557
558 //
559 // File Name Alignment Fix (FNAF)
560 // Handle2->Open may be incapable of handling a unaligned CHAR16 data.
561 // The structure pointed to by FilePath may be not CHAR16 aligned.
562 // This code copies the potentially unaligned PathName data from the
563 // FilePath structure to the aligned FnafPathName for use in the
564 // calls to Handl2->Open.
565 //
566
567 //
568 // Determine length of PathName, in bytes.
569 //
570 PathLen = DevicePathNodeLength (*FilePath) - SIZE_OF_FILEPATH_DEVICE_PATH;
571
572 //
573 // Allocate memory for the aligned copy of the string Extra allocation is to allow for forced alignment
574 // Copy bytes from possibly unaligned location to aligned location
575 //
576 FnafPathName = AllocateCopyPool(PathLen, (UINT8 *)((FILEPATH_DEVICE_PATH*)*FilePath)->PathName);
577 if (FnafPathName == NULL) {
578 return EFI_OUT_OF_RESOURCES;
579 }
580
581 //
582 // Try to test opening an existing file
583 //
584 Status = Handle2->Open (
585 Handle2,
586 &Handle1,
587 FnafPathName,
588 OpenMode &~EFI_FILE_MODE_CREATE,
589 0
590 );
591
592 //
593 // see if the error was that it needs to be created
594 //
595 if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
596 Status = Handle2->Open (
597 Handle2,
598 &Handle1,
599 FnafPathName,
600 OpenMode,
601 Attributes
602 );
603 }
604
605 //
606 // Free the alignment buffer
607 //
608 FreePool(FnafPathName);
609
610 //
611 // Close the last node
612 //
613 Handle2->Close (Handle2);
614
615 if (EFI_ERROR(Status)) {
616 return (Status);
617 }
618
619 //
620 // Get the next node
621 //
622 *FilePath = NextDevicePathNode (*FilePath);
623 }
624
625 //
626 // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
627 //
628 *FileHandle = (VOID*)Handle1;
629 return (EFI_SUCCESS);
630 }
631
632 /**
633 This function will open a file or directory referenced by filename.
634
635 If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
636 otherwise, the Filehandle is NULL. The Attributes is valid only for
637 EFI_FILE_MODE_CREATE.
638
639 if FileName is NULL then ASSERT()
640
641 @param FileName pointer to file name
642 @param FileHandle pointer to the file handle.
643 @param OpenMode the mode to open the file with.
644 @param Attributes the file's file attributes.
645
646 @retval EFI_SUCCESS The information was set.
647 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
648 @retval EFI_UNSUPPORTED Could not open the file path.
649 @retval EFI_NOT_FOUND The specified file could not be found on the
650 device or the file system could not be found
651 on the device.
652 @retval EFI_NO_MEDIA The device has no medium.
653 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
654 medium is no longer supported.
655 @retval EFI_DEVICE_ERROR The device reported an error.
656 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
657 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
658 @retval EFI_ACCESS_DENIED The file was opened read only.
659 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
660 file.
661 @retval EFI_VOLUME_FULL The volume is full.
662 **/
663 EFI_STATUS
664 EFIAPI
665 ShellOpenFileByName(
666 IN CONST CHAR16 *FileName,
667 OUT SHELL_FILE_HANDLE *FileHandle,
668 IN UINT64 OpenMode,
669 IN UINT64 Attributes
670 )
671 {
672 EFI_HANDLE DeviceHandle;
673 EFI_DEVICE_PATH_PROTOCOL *FilePath;
674 EFI_STATUS Status;
675 EFI_FILE_INFO *FileInfo;
676 CHAR16 *FileNameCopy;
677 EFI_STATUS Status2;
678
679 //
680 // ASSERT if FileName is NULL
681 //
682 ASSERT(FileName != NULL);
683
684 if (FileName == NULL) {
685 return (EFI_INVALID_PARAMETER);
686 }
687
688 if (gEfiShellProtocol != NULL) {
689 if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {
690
691 //
692 // Create only a directory
693 //
694 if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
695 return ShellCreateDirectory(FileName, FileHandle);
696 }
697
698 //
699 // Create the directory to create the file in
700 //
701 FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
702 if (FileName == NULL) {
703 return (EFI_OUT_OF_RESOURCES);
704 }
705 PathCleanUpDirectories (FileNameCopy);
706 if (PathRemoveLastItem (FileNameCopy)) {
707 if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) {
708 ShellCloseFile (FileHandle);
709 }
710 }
711 SHELL_FREE_NON_NULL (FileNameCopy);
712 }
713
714 //
715 // Use UEFI Shell 2.0 method to create the file
716 //
717 Status = gEfiShellProtocol->OpenFileByName(FileName,
718 FileHandle,
719 OpenMode);
720 if (StrCmp(FileName, L"NUL") != 0 && !EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){
721 FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);
722 ASSERT(FileInfo != NULL);
723 FileInfo->Attribute = Attributes;
724 Status2 = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);
725 FreePool(FileInfo);
726 if (EFI_ERROR (Status2)) {
727 gEfiShellProtocol->CloseFile(*FileHandle);
728 }
729 Status = Status2;
730 }
731 return (Status);
732 }
733 //
734 // Using EFI Shell version
735 // this means convert name to path and call that function
736 // since this will use EFI method again that will open it.
737 //
738 ASSERT(mEfiShellEnvironment2 != NULL);
739 FilePath = mEfiShellEnvironment2->NameToPath ((CHAR16*)FileName);
740 if (FilePath != NULL) {
741 return (ShellOpenFileByDevicePath(&FilePath,
742 &DeviceHandle,
743 FileHandle,
744 OpenMode,
745 Attributes));
746 }
747 return (EFI_DEVICE_ERROR);
748 }
749 /**
750 This function create a directory
751
752 If return is EFI_SUCCESS, the Filehandle is the opened directory's handle;
753 otherwise, the Filehandle is NULL. If the directory already existed, this
754 function opens the existing directory.
755
756 @param DirectoryName pointer to directory name
757 @param FileHandle pointer to the file handle.
758
759 @retval EFI_SUCCESS The information was set.
760 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
761 @retval EFI_UNSUPPORTED Could not open the file path.
762 @retval EFI_NOT_FOUND The specified file could not be found on the
763 device or the file system could not be found
764 on the device.
765 @retval EFI_NO_MEDIA The device has no medium.
766 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
767 medium is no longer supported.
768 @retval EFI_DEVICE_ERROR The device reported an error.
769 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
770 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
771 @retval EFI_ACCESS_DENIED The file was opened read only.
772 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
773 file.
774 @retval EFI_VOLUME_FULL The volume is full.
775 @sa ShellOpenFileByName
776 **/
777 EFI_STATUS
778 EFIAPI
779 ShellCreateDirectory(
780 IN CONST CHAR16 *DirectoryName,
781 OUT SHELL_FILE_HANDLE *FileHandle
782 )
783 {
784 if (gEfiShellProtocol != NULL) {
785 //
786 // Use UEFI Shell 2.0 method
787 //
788 return (gEfiShellProtocol->CreateFile(DirectoryName,
789 EFI_FILE_DIRECTORY,
790 FileHandle
791 ));
792 } else {
793 return (ShellOpenFileByName(DirectoryName,
794 FileHandle,
795 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,
796 EFI_FILE_DIRECTORY
797 ));
798 }
799 }
800
801 /**
802 This function reads information from an opened file.
803
804 If FileHandle is not a directory, the function reads the requested number of
805 bytes from the file at the file's current position and returns them in Buffer.
806 If the read goes beyond the end of the file, the read length is truncated to the
807 end of the file. The file's current position is increased by the number of bytes
808 returned. If FileHandle is a directory, the function reads the directory entry
809 at the file's current position and returns the entry in Buffer. If the Buffer
810 is not large enough to hold the current directory entry, then
811 EFI_BUFFER_TOO_SMALL is returned and the current file position is not updated.
812 BufferSize is set to be the size of the buffer needed to read the entry. On
813 success, the current position is updated to the next directory entry. If there
814 are no more directory entries, the read returns a zero-length buffer.
815 EFI_FILE_INFO is the structure returned as the directory entry.
816
817 @param FileHandle the opened file handle
818 @param BufferSize on input the size of buffer in bytes. on return
819 the number of bytes written.
820 @param Buffer the buffer to put read data into.
821
822 @retval EFI_SUCCESS Data was read.
823 @retval EFI_NO_MEDIA The device has no media.
824 @retval EFI_DEVICE_ERROR The device reported an error.
825 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
826 @retval EFI_BUFFER_TO_SMALL Buffer is too small. ReadSize contains required
827 size.
828
829 **/
830 EFI_STATUS
831 EFIAPI
832 ShellReadFile(
833 IN SHELL_FILE_HANDLE FileHandle,
834 IN OUT UINTN *BufferSize,
835 OUT VOID *Buffer
836 )
837 {
838 return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer));
839 }
840
841
842 /**
843 Write data to a file.
844
845 This function writes the specified number of bytes to the file at the current
846 file position. The current file position is advanced the actual number of bytes
847 written, which is returned in BufferSize. Partial writes only occur when there
848 has been a data error during the write attempt (such as "volume space full").
849 The file is automatically grown to hold the data if required. Direct writes to
850 opened directories are not supported.
851
852 @param FileHandle The opened file for writing
853 @param BufferSize on input the number of bytes in Buffer. On output
854 the number of bytes written.
855 @param Buffer the buffer containing data to write is stored.
856
857 @retval EFI_SUCCESS Data was written.
858 @retval EFI_UNSUPPORTED Writes to an open directory are not supported.
859 @retval EFI_NO_MEDIA The device has no media.
860 @retval EFI_DEVICE_ERROR The device reported an error.
861 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
862 @retval EFI_WRITE_PROTECTED The device is write-protected.
863 @retval EFI_ACCESS_DENIED The file was open for read only.
864 @retval EFI_VOLUME_FULL The volume is full.
865 **/
866 EFI_STATUS
867 EFIAPI
868 ShellWriteFile(
869 IN SHELL_FILE_HANDLE FileHandle,
870 IN OUT UINTN *BufferSize,
871 IN VOID *Buffer
872 )
873 {
874 return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer));
875 }
876
877 /**
878 Close an open file handle.
879
880 This function closes a specified file handle. All "dirty" cached file data is
881 flushed to the device, and the file is closed. In all cases the handle is
882 closed.
883
884 @param FileHandle the file handle to close.
885
886 @retval EFI_SUCCESS the file handle was closed sucessfully.
887 **/
888 EFI_STATUS
889 EFIAPI
890 ShellCloseFile (
891 IN SHELL_FILE_HANDLE *FileHandle
892 )
893 {
894 return (FileFunctionMap.CloseFile(*FileHandle));
895 }
896
897 /**
898 Delete a file and close the handle
899
900 This function closes and deletes a file. In all cases the file handle is closed.
901 If the file cannot be deleted, the warning code EFI_WARN_DELETE_FAILURE is
902 returned, but the handle is still closed.
903
904 @param FileHandle the file handle to delete
905
906 @retval EFI_SUCCESS the file was closed sucessfully
907 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
908 deleted
909 @retval INVALID_PARAMETER One of the parameters has an invalid value.
910 **/
911 EFI_STATUS
912 EFIAPI
913 ShellDeleteFile (
914 IN SHELL_FILE_HANDLE *FileHandle
915 )
916 {
917 return (FileFunctionMap.DeleteFile(*FileHandle));
918 }
919
920 /**
921 Set the current position in a file.
922
923 This function sets the current file position for the handle to the position
924 supplied. With the exception of seeking to position 0xFFFFFFFFFFFFFFFF, only
925 absolute positioning is supported, and seeking past the end of the file is
926 allowed (a subsequent write would grow the file). Seeking to position
927 0xFFFFFFFFFFFFFFFF causes the current position to be set to the end of the file.
928 If FileHandle is a directory, the only position that may be set is zero. This
929 has the effect of starting the read process of the directory entries over.
930
931 @param FileHandle The file handle on which the position is being set
932 @param Position Byte position from begining of file
933
934 @retval EFI_SUCCESS Operation completed sucessfully.
935 @retval EFI_UNSUPPORTED the seek request for non-zero is not valid on
936 directories.
937 @retval INVALID_PARAMETER One of the parameters has an invalid value.
938 **/
939 EFI_STATUS
940 EFIAPI
941 ShellSetFilePosition (
942 IN SHELL_FILE_HANDLE FileHandle,
943 IN UINT64 Position
944 )
945 {
946 return (FileFunctionMap.SetFilePosition(FileHandle, Position));
947 }
948
949 /**
950 Gets a file's current position
951
952 This function retrieves the current file position for the file handle. For
953 directories, the current file position has no meaning outside of the file
954 system driver and as such the operation is not supported. An error is returned
955 if FileHandle is a directory.
956
957 @param FileHandle The open file handle on which to get the position.
958 @param Position Byte position from begining of file.
959
960 @retval EFI_SUCCESS the operation completed sucessfully.
961 @retval INVALID_PARAMETER One of the parameters has an invalid value.
962 @retval EFI_UNSUPPORTED the request is not valid on directories.
963 **/
964 EFI_STATUS
965 EFIAPI
966 ShellGetFilePosition (
967 IN SHELL_FILE_HANDLE FileHandle,
968 OUT UINT64 *Position
969 )
970 {
971 return (FileFunctionMap.GetFilePosition(FileHandle, Position));
972 }
973 /**
974 Flushes data on a file
975
976 This function flushes all modified data associated with a file to a device.
977
978 @param FileHandle The file handle on which to flush data
979
980 @retval EFI_SUCCESS The data was flushed.
981 @retval EFI_NO_MEDIA The device has no media.
982 @retval EFI_DEVICE_ERROR The device reported an error.
983 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
984 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
985 @retval EFI_ACCESS_DENIED The file was opened for read only.
986 **/
987 EFI_STATUS
988 EFIAPI
989 ShellFlushFile (
990 IN SHELL_FILE_HANDLE FileHandle
991 )
992 {
993 return (FileFunctionMap.FlushFile(FileHandle));
994 }
995
996 /** Retrieve first entry from a directory.
997
998 This function takes an open directory handle and gets information from the
999 first entry in the directory. A buffer is allocated to contain
1000 the information and a pointer to the buffer is returned in *Buffer. The
1001 caller can use ShellFindNextFile() to get subsequent directory entries.
1002
1003 The buffer will be freed by ShellFindNextFile() when the last directory
1004 entry is read. Otherwise, the caller must free the buffer, using FreePool,
1005 when finished with it.
1006
1007 @param[in] DirHandle The file handle of the directory to search.
1008 @param[out] Buffer The pointer to the buffer for the file's information.
1009
1010 @retval EFI_SUCCESS Found the first file.
1011 @retval EFI_NOT_FOUND Cannot find the directory.
1012 @retval EFI_NO_MEDIA The device has no media.
1013 @retval EFI_DEVICE_ERROR The device reported an error.
1014 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1015 @return Others status of ShellGetFileInfo, ShellSetFilePosition,
1016 or ShellReadFile
1017 **/
1018 EFI_STATUS
1019 EFIAPI
1020 ShellFindFirstFile (
1021 IN SHELL_FILE_HANDLE DirHandle,
1022 OUT EFI_FILE_INFO **Buffer
1023 )
1024 {
1025 //
1026 // pass to file handle lib
1027 //
1028 return (FileHandleFindFirstFile(DirHandle, Buffer));
1029 }
1030 /** Retrieve next entries from a directory.
1031
1032 To use this function, the caller must first call the ShellFindFirstFile()
1033 function to get the first directory entry. Subsequent directory entries are
1034 retrieved by using the ShellFindNextFile() function. This function can
1035 be called several times to get each entry from the directory. If the call of
1036 ShellFindNextFile() retrieved the last directory entry, the next call of
1037 this function will set *NoFile to TRUE and free the buffer.
1038
1039 @param[in] DirHandle The file handle of the directory.
1040 @param[out] Buffer The pointer to buffer for file's information.
1041 @param[out] NoFile The pointer to boolean when last file is found.
1042
1043 @retval EFI_SUCCESS Found the next file, or reached last file
1044 @retval EFI_NO_MEDIA The device has no media.
1045 @retval EFI_DEVICE_ERROR The device reported an error.
1046 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1047 **/
1048 EFI_STATUS
1049 EFIAPI
1050 ShellFindNextFile(
1051 IN SHELL_FILE_HANDLE DirHandle,
1052 OUT EFI_FILE_INFO *Buffer,
1053 OUT BOOLEAN *NoFile
1054 )
1055 {
1056 //
1057 // pass to file handle lib
1058 //
1059 return (FileHandleFindNextFile(DirHandle, Buffer, NoFile));
1060 }
1061 /**
1062 Retrieve the size of a file.
1063
1064 if FileHandle is NULL then ASSERT()
1065 if Size is NULL then ASSERT()
1066
1067 This function extracts the file size info from the FileHandle's EFI_FILE_INFO
1068 data.
1069
1070 @param FileHandle file handle from which size is retrieved
1071 @param Size pointer to size
1072
1073 @retval EFI_SUCCESS operation was completed sucessfully
1074 @retval EFI_DEVICE_ERROR cannot access the file
1075 **/
1076 EFI_STATUS
1077 EFIAPI
1078 ShellGetFileSize (
1079 IN SHELL_FILE_HANDLE FileHandle,
1080 OUT UINT64 *Size
1081 )
1082 {
1083 return (FileFunctionMap.GetFileSize(FileHandle, Size));
1084 }
1085 /**
1086 Retrieves the status of the break execution flag
1087
1088 this function is useful to check whether the application is being asked to halt by the shell.
1089
1090 @retval TRUE the execution break is enabled
1091 @retval FALSE the execution break is not enabled
1092 **/
1093 BOOLEAN
1094 EFIAPI
1095 ShellGetExecutionBreakFlag(
1096 VOID
1097 )
1098 {
1099 //
1100 // Check for UEFI Shell 2.0 protocols
1101 //
1102 if (gEfiShellProtocol != NULL) {
1103
1104 //
1105 // We are using UEFI Shell 2.0; see if the event has been triggered
1106 //
1107 if (gBS->CheckEvent(gEfiShellProtocol->ExecutionBreak) != EFI_SUCCESS) {
1108 return (FALSE);
1109 }
1110 return (TRUE);
1111 }
1112
1113 //
1114 // using EFI Shell; call the function to check
1115 //
1116 if (mEfiShellEnvironment2 != NULL) {
1117 return (mEfiShellEnvironment2->GetExecutionBreak());
1118 }
1119
1120 return (FALSE);
1121 }
1122 /**
1123 return the value of an environment variable
1124
1125 this function gets the value of the environment variable set by the
1126 ShellSetEnvironmentVariable function
1127
1128 @param EnvKey The key name of the environment variable.
1129
1130 @retval NULL the named environment variable does not exist.
1131 @return != NULL pointer to the value of the environment variable
1132 **/
1133 CONST CHAR16*
1134 EFIAPI
1135 ShellGetEnvironmentVariable (
1136 IN CONST CHAR16 *EnvKey
1137 )
1138 {
1139 //
1140 // Check for UEFI Shell 2.0 protocols
1141 //
1142 if (gEfiShellProtocol != NULL) {
1143 return (gEfiShellProtocol->GetEnv(EnvKey));
1144 }
1145
1146 //
1147 // Check for EFI shell
1148 //
1149 if (mEfiShellEnvironment2 != NULL) {
1150 return (mEfiShellEnvironment2->GetEnv((CHAR16*)EnvKey));
1151 }
1152
1153 return NULL;
1154 }
1155 /**
1156 set the value of an environment variable
1157
1158 This function changes the current value of the specified environment variable. If the
1159 environment variable exists and the Value is an empty string, then the environment
1160 variable is deleted. If the environment variable exists and the Value is not an empty
1161 string, then the value of the environment variable is changed. If the environment
1162 variable does not exist and the Value is an empty string, there is no action. If the
1163 environment variable does not exist and the Value is a non-empty string, then the
1164 environment variable is created and assigned the specified value.
1165
1166 This is not supported pre-UEFI Shell 2.0.
1167
1168 @param EnvKey The key name of the environment variable.
1169 @param EnvVal The Value of the environment variable
1170 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
1171
1172 @retval EFI_SUCCESS the operation was completed sucessfully
1173 @retval EFI_UNSUPPORTED This operation is not allowed in pre UEFI 2.0 Shell environments
1174 **/
1175 EFI_STATUS
1176 EFIAPI
1177 ShellSetEnvironmentVariable (
1178 IN CONST CHAR16 *EnvKey,
1179 IN CONST CHAR16 *EnvVal,
1180 IN BOOLEAN Volatile
1181 )
1182 {
1183 //
1184 // Check for UEFI Shell 2.0 protocols
1185 //
1186 if (gEfiShellProtocol != NULL) {
1187 return (gEfiShellProtocol->SetEnv(EnvKey, EnvVal, Volatile));
1188 }
1189
1190 //
1191 // This feature does not exist under EFI shell
1192 //
1193 return (EFI_UNSUPPORTED);
1194 }
1195
1196 /**
1197 Cause the shell to parse and execute a command line.
1198
1199 This function creates a nested instance of the shell and executes the specified
1200 command (CommandLine) with the specified environment (Environment). Upon return,
1201 the status code returned by the specified command is placed in StatusCode.
1202 If Environment is NULL, then the current environment is used and all changes made
1203 by the commands executed will be reflected in the current environment. If the
1204 Environment is non-NULL, then the changes made will be discarded.
1205 The CommandLine is executed from the current working directory on the current
1206 device.
1207
1208 The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0
1209 environment. The values pointed to by the parameters will be unchanged by the
1210 ShellExecute() function. The Output parameter has no effect in a
1211 UEFI Shell 2.0 environment.
1212
1213 @param[in] ParentHandle The parent image starting the operation.
1214 @param[in] CommandLine The pointer to a NULL terminated command line.
1215 @param[in] Output True to display debug output. False to hide it.
1216 @param[in] EnvironmentVariables Optional pointer to array of environment variables
1217 in the form "x=y". If NULL, the current set is used.
1218 @param[out] Status The status of the run command line.
1219
1220 @retval EFI_SUCCESS The operation completed sucessfully. Status
1221 contains the status code returned.
1222 @retval EFI_INVALID_PARAMETER A parameter contains an invalid value.
1223 @retval EFI_OUT_OF_RESOURCES Out of resources.
1224 @retval EFI_UNSUPPORTED The operation is not allowed.
1225 **/
1226 EFI_STATUS
1227 EFIAPI
1228 ShellExecute (
1229 IN EFI_HANDLE *ParentHandle,
1230 IN CHAR16 *CommandLine OPTIONAL,
1231 IN BOOLEAN Output OPTIONAL,
1232 IN CHAR16 **EnvironmentVariables OPTIONAL,
1233 OUT EFI_STATUS *Status OPTIONAL
1234 )
1235 {
1236 EFI_STATUS CmdStatus;
1237 //
1238 // Check for UEFI Shell 2.0 protocols
1239 //
1240 if (gEfiShellProtocol != NULL) {
1241 //
1242 // Call UEFI Shell 2.0 version (not using Output parameter)
1243 //
1244 return (gEfiShellProtocol->Execute(ParentHandle,
1245 CommandLine,
1246 EnvironmentVariables,
1247 Status));
1248 }
1249
1250 //
1251 // Check for EFI shell
1252 //
1253 if (mEfiShellEnvironment2 != NULL) {
1254 //
1255 // Call EFI Shell version.
1256 // Due to oddity in the EFI shell we want to dereference the ParentHandle here
1257 //
1258 CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,
1259 CommandLine,
1260 Output));
1261 //
1262 // No Status output parameter so just use the returned status
1263 //
1264 if (Status != NULL) {
1265 *Status = CmdStatus;
1266 }
1267 //
1268 // If there was an error, we can't tell if it was from the command or from
1269 // the Execute() function, so we'll just assume the shell ran successfully
1270 // and the error came from the command.
1271 //
1272 return EFI_SUCCESS;
1273 }
1274
1275 return (EFI_UNSUPPORTED);
1276 }
1277
1278 /**
1279 Retreives the current directory path
1280
1281 If the DeviceName is NULL, it returns the current device's current directory
1282 name. If the DeviceName is not NULL, it returns the current directory name
1283 on specified drive.
1284
1285 Note that the current directory string should exclude the tailing backslash character.
1286
1287 @param DeviceName the name of the drive to get directory on
1288
1289 @retval NULL the directory does not exist
1290 @return != NULL the directory
1291 **/
1292 CONST CHAR16*
1293 EFIAPI
1294 ShellGetCurrentDir (
1295 IN CHAR16 * CONST DeviceName OPTIONAL
1296 )
1297 {
1298 //
1299 // Check for UEFI Shell 2.0 protocols
1300 //
1301 if (gEfiShellProtocol != NULL) {
1302 return (gEfiShellProtocol->GetCurDir(DeviceName));
1303 }
1304
1305 //
1306 // Check for EFI shell
1307 //
1308 if (mEfiShellEnvironment2 != NULL) {
1309 return (mEfiShellEnvironment2->CurDir(DeviceName));
1310 }
1311
1312 return (NULL);
1313 }
1314 /**
1315 sets (enabled or disabled) the page break mode
1316
1317 when page break mode is enabled the screen will stop scrolling
1318 and wait for operator input before scrolling a subsequent screen.
1319
1320 @param CurrentState TRUE to enable and FALSE to disable
1321 **/
1322 VOID
1323 EFIAPI
1324 ShellSetPageBreakMode (
1325 IN BOOLEAN CurrentState
1326 )
1327 {
1328 //
1329 // check for enabling
1330 //
1331 if (CurrentState != 0x00) {
1332 //
1333 // check for UEFI Shell 2.0
1334 //
1335 if (gEfiShellProtocol != NULL) {
1336 //
1337 // Enable with UEFI 2.0 Shell
1338 //
1339 gEfiShellProtocol->EnablePageBreak();
1340 return;
1341 } else {
1342 //
1343 // Check for EFI shell
1344 //
1345 if (mEfiShellEnvironment2 != NULL) {
1346 //
1347 // Enable with EFI Shell
1348 //
1349 mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);
1350 return;
1351 }
1352 }
1353 } else {
1354 //
1355 // check for UEFI Shell 2.0
1356 //
1357 if (gEfiShellProtocol != NULL) {
1358 //
1359 // Disable with UEFI 2.0 Shell
1360 //
1361 gEfiShellProtocol->DisablePageBreak();
1362 return;
1363 } else {
1364 //
1365 // Check for EFI shell
1366 //
1367 if (mEfiShellEnvironment2 != NULL) {
1368 //
1369 // Disable with EFI Shell
1370 //
1371 mEfiShellEnvironment2->DisablePageBreak ();
1372 return;
1373 }
1374 }
1375 }
1376 }
1377
1378 ///
1379 /// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.
1380 /// This allows for the struct to be populated.
1381 ///
1382 typedef struct {
1383 LIST_ENTRY Link;
1384 EFI_STATUS Status;
1385 CHAR16 *FullName;
1386 CHAR16 *FileName;
1387 SHELL_FILE_HANDLE Handle;
1388 EFI_FILE_INFO *Info;
1389 } EFI_SHELL_FILE_INFO_NO_CONST;
1390
1391 /**
1392 Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.
1393
1394 if OldStyleFileList is NULL then ASSERT()
1395
1396 this function will convert a SHELL_FILE_ARG based list into a callee allocated
1397 EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via
1398 the ShellCloseFileMetaArg function.
1399
1400 @param[in] FileList the EFI shell list type
1401 @param[in, out] ListHead the list to add to
1402
1403 @retval the resultant head of the double linked new format list;
1404 **/
1405 LIST_ENTRY*
1406 EFIAPI
1407 InternalShellConvertFileListType (
1408 IN LIST_ENTRY *FileList,
1409 IN OUT LIST_ENTRY *ListHead
1410 )
1411 {
1412 SHELL_FILE_ARG *OldInfo;
1413 LIST_ENTRY *Link;
1414 EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;
1415
1416 //
1417 // ASSERTs
1418 //
1419 ASSERT(FileList != NULL);
1420 ASSERT(ListHead != NULL);
1421
1422 //
1423 // enumerate through each member of the old list and copy
1424 //
1425 for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {
1426 OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);
1427 ASSERT(OldInfo != NULL);
1428
1429 //
1430 // Skip ones that failed to open...
1431 //
1432 if (OldInfo->Status != EFI_SUCCESS) {
1433 continue;
1434 }
1435
1436 //
1437 // make sure the old list was valid
1438 //
1439 ASSERT(OldInfo->Info != NULL);
1440 ASSERT(OldInfo->FullName != NULL);
1441 ASSERT(OldInfo->FileName != NULL);
1442
1443 //
1444 // allocate a new EFI_SHELL_FILE_INFO object
1445 //
1446 NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1447 if (NewInfo == NULL) {
1448 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
1449 ListHead = NULL;
1450 break;
1451 }
1452
1453 //
1454 // copy the simple items
1455 //
1456 NewInfo->Handle = OldInfo->Handle;
1457 NewInfo->Status = OldInfo->Status;
1458
1459 // old shell checks for 0 not NULL
1460 OldInfo->Handle = 0;
1461
1462 //
1463 // allocate new space to copy strings and structure
1464 //
1465 NewInfo->FullName = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);
1466 NewInfo->FileName = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);
1467 NewInfo->Info = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);
1468
1469 //
1470 // make sure all the memory allocations were sucessful
1471 //
1472 if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {
1473 //
1474 // Free the partially allocated new node
1475 //
1476 SHELL_FREE_NON_NULL(NewInfo->FullName);
1477 SHELL_FREE_NON_NULL(NewInfo->FileName);
1478 SHELL_FREE_NON_NULL(NewInfo->Info);
1479 SHELL_FREE_NON_NULL(NewInfo);
1480
1481 //
1482 // Free the previously converted stuff
1483 //
1484 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));
1485 ListHead = NULL;
1486 break;
1487 }
1488
1489 //
1490 // add that to the list
1491 //
1492 InsertTailList(ListHead, &NewInfo->Link);
1493 }
1494 return (ListHead);
1495 }
1496 /**
1497 Opens a group of files based on a path.
1498
1499 This function uses the Arg to open all the matching files. Each matched
1500 file has a SHELL_FILE_INFO structure to record the file information. These
1501 structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO
1502 structures from ListHead to access each file. This function supports wildcards
1503 and will process '?' and '*' as such. the list must be freed with a call to
1504 ShellCloseFileMetaArg().
1505
1506 If you are NOT appending to an existing list *ListHead must be NULL. If
1507 *ListHead is NULL then it must be callee freed.
1508
1509 @param Arg pointer to path string
1510 @param OpenMode mode to open files with
1511 @param ListHead head of linked list of results
1512
1513 @retval EFI_SUCCESS the operation was sucessful and the list head
1514 contains the list of opened files
1515 @return != EFI_SUCCESS the operation failed
1516
1517 @sa InternalShellConvertFileListType
1518 **/
1519 EFI_STATUS
1520 EFIAPI
1521 ShellOpenFileMetaArg (
1522 IN CHAR16 *Arg,
1523 IN UINT64 OpenMode,
1524 IN OUT EFI_SHELL_FILE_INFO **ListHead
1525 )
1526 {
1527 EFI_STATUS Status;
1528 LIST_ENTRY mOldStyleFileList;
1529 CHAR16 *CleanFilePathStr;
1530
1531 //
1532 // ASSERT that Arg and ListHead are not NULL
1533 //
1534 ASSERT(Arg != NULL);
1535 ASSERT(ListHead != NULL);
1536
1537 CleanFilePathStr = NULL;
1538
1539 Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);
1540 if (EFI_ERROR (Status)) {
1541 return Status;
1542 }
1543
1544 //
1545 // Check for UEFI Shell 2.0 protocols
1546 //
1547 if (gEfiShellProtocol != NULL) {
1548 if (*ListHead == NULL) {
1549 *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1550 if (*ListHead == NULL) {
1551 FreePool(CleanFilePathStr);
1552 return (EFI_OUT_OF_RESOURCES);
1553 }
1554 InitializeListHead(&((*ListHead)->Link));
1555 }
1556 Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr,
1557 OpenMode,
1558 ListHead);
1559 if (EFI_ERROR(Status)) {
1560 gEfiShellProtocol->RemoveDupInFileList(ListHead);
1561 } else {
1562 Status = gEfiShellProtocol->RemoveDupInFileList(ListHead);
1563 }
1564 if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) {
1565 FreePool(*ListHead);
1566 FreePool(CleanFilePathStr);
1567 *ListHead = NULL;
1568 return (EFI_NOT_FOUND);
1569 }
1570 FreePool(CleanFilePathStr);
1571 return (Status);
1572 }
1573
1574 //
1575 // Check for EFI shell
1576 //
1577 if (mEfiShellEnvironment2 != NULL) {
1578 //
1579 // make sure the list head is initialized
1580 //
1581 InitializeListHead(&mOldStyleFileList);
1582
1583 //
1584 // Get the EFI Shell list of files
1585 //
1586 Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList);
1587 if (EFI_ERROR(Status)) {
1588 *ListHead = NULL;
1589 FreePool(CleanFilePathStr);
1590 return (Status);
1591 }
1592
1593 if (*ListHead == NULL) {
1594 *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));
1595 if (*ListHead == NULL) {
1596 FreePool(CleanFilePathStr);
1597 return (EFI_OUT_OF_RESOURCES);
1598 }
1599 InitializeListHead(&((*ListHead)->Link));
1600 }
1601
1602 //
1603 // Convert that to equivalent of UEFI Shell 2.0 structure
1604 //
1605 InternalShellConvertFileListType(&mOldStyleFileList, &(*ListHead)->Link);
1606
1607 //
1608 // Free the EFI Shell version that was converted.
1609 //
1610 mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList);
1611
1612 if ((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink && (*ListHead)->Link.BackLink == &((*ListHead)->Link)) {
1613 FreePool(*ListHead);
1614 *ListHead = NULL;
1615 Status = EFI_NOT_FOUND;
1616 }
1617 FreePool(CleanFilePathStr);
1618 return (Status);
1619 }
1620
1621 FreePool(CleanFilePathStr);
1622 return (EFI_UNSUPPORTED);
1623 }
1624 /**
1625 Free the linked list returned from ShellOpenFileMetaArg.
1626
1627 if ListHead is NULL then ASSERT().
1628
1629 @param ListHead the pointer to free.
1630
1631 @retval EFI_SUCCESS the operation was sucessful.
1632 **/
1633 EFI_STATUS
1634 EFIAPI
1635 ShellCloseFileMetaArg (
1636 IN OUT EFI_SHELL_FILE_INFO **ListHead
1637 )
1638 {
1639 LIST_ENTRY *Node;
1640
1641 //
1642 // ASSERT that ListHead is not NULL
1643 //
1644 ASSERT(ListHead != NULL);
1645
1646 //
1647 // Check for UEFI Shell 2.0 protocols
1648 //
1649 if (gEfiShellProtocol != NULL) {
1650 return (gEfiShellProtocol->FreeFileList(ListHead));
1651 } else if (mEfiShellEnvironment2 != NULL) {
1652 //
1653 // Since this is EFI Shell version we need to free our internally made copy
1654 // of the list
1655 //
1656 for ( Node = GetFirstNode(&(*ListHead)->Link)
1657 ; *ListHead != NULL && !IsListEmpty(&(*ListHead)->Link)
1658 ; Node = GetFirstNode(&(*ListHead)->Link)) {
1659 RemoveEntryList(Node);
1660 ((EFI_FILE_PROTOCOL*)((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle)->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle);
1661 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);
1662 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName);
1663 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);
1664 FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);
1665 }
1666 SHELL_FREE_NON_NULL(*ListHead);
1667 return EFI_SUCCESS;
1668 }
1669
1670 return (EFI_UNSUPPORTED);
1671 }
1672
1673 /**
1674 Find a file by searching the CWD and then the path.
1675
1676 If FileName is NULL then ASSERT.
1677
1678 If the return value is not NULL then the memory must be caller freed.
1679
1680 @param FileName Filename string.
1681
1682 @retval NULL the file was not found
1683 @return !NULL the full path to the file.
1684 **/
1685 CHAR16 *
1686 EFIAPI
1687 ShellFindFilePath (
1688 IN CONST CHAR16 *FileName
1689 )
1690 {
1691 CONST CHAR16 *Path;
1692 SHELL_FILE_HANDLE Handle;
1693 EFI_STATUS Status;
1694 CHAR16 *RetVal;
1695 CHAR16 *TestPath;
1696 CONST CHAR16 *Walker;
1697 UINTN Size;
1698 CHAR16 *TempChar;
1699
1700 RetVal = NULL;
1701
1702 //
1703 // First make sure its not an absolute path.
1704 //
1705 Status = ShellOpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ, 0);
1706 if (!EFI_ERROR(Status)){
1707 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1708 ASSERT(RetVal == NULL);
1709 RetVal = StrnCatGrow(&RetVal, NULL, FileName, 0);
1710 ShellCloseFile(&Handle);
1711 return (RetVal);
1712 } else {
1713 ShellCloseFile(&Handle);
1714 }
1715 }
1716
1717 Path = ShellGetEnvironmentVariable(L"cwd");
1718 if (Path != NULL) {
1719 Size = StrSize(Path) + sizeof(CHAR16);
1720 Size += StrSize(FileName);
1721 TestPath = AllocateZeroPool(Size);
1722 if (TestPath == NULL) {
1723 return (NULL);
1724 }
1725 StrCpyS(TestPath, Size/sizeof(CHAR16), Path);
1726 StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
1727 StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
1728 Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
1729 if (!EFI_ERROR(Status)){
1730 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1731 ASSERT(RetVal == NULL);
1732 RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);
1733 ShellCloseFile(&Handle);
1734 FreePool(TestPath);
1735 return (RetVal);
1736 } else {
1737 ShellCloseFile(&Handle);
1738 }
1739 }
1740 FreePool(TestPath);
1741 }
1742 Path = ShellGetEnvironmentVariable(L"path");
1743 if (Path != NULL) {
1744 Size = StrSize(Path)+sizeof(CHAR16);
1745 Size += StrSize(FileName);
1746 TestPath = AllocateZeroPool(Size);
1747 if (TestPath == NULL) {
1748 return (NULL);
1749 }
1750 Walker = (CHAR16*)Path;
1751 do {
1752 CopyMem(TestPath, Walker, StrSize(Walker));
1753 if (TestPath != NULL) {
1754 TempChar = StrStr(TestPath, L";");
1755 if (TempChar != NULL) {
1756 *TempChar = CHAR_NULL;
1757 }
1758 if (TestPath[StrLen(TestPath)-1] != L'\\') {
1759 StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");
1760 }
1761 if (FileName[0] == L'\\') {
1762 FileName++;
1763 }
1764 StrCatS(TestPath, Size/sizeof(CHAR16), FileName);
1765 if (StrStr(Walker, L";") != NULL) {
1766 Walker = StrStr(Walker, L";") + 1;
1767 } else {
1768 Walker = NULL;
1769 }
1770 Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);
1771 if (!EFI_ERROR(Status)){
1772 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
1773 ASSERT(RetVal == NULL);
1774 RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);
1775 ShellCloseFile(&Handle);
1776 break;
1777 } else {
1778 ShellCloseFile(&Handle);
1779 }
1780 }
1781 }
1782 } while (Walker != NULL && Walker[0] != CHAR_NULL);
1783 FreePool(TestPath);
1784 }
1785 return (RetVal);
1786 }
1787
1788 /**
1789 Find a file by searching the CWD and then the path with a variable set of file
1790 extensions. If the file is not found it will append each extension in the list
1791 in the order provided and return the first one that is successful.
1792
1793 If FileName is NULL, then ASSERT.
1794 If FileExtension is NULL, then behavior is identical to ShellFindFilePath.
1795
1796 If the return value is not NULL then the memory must be caller freed.
1797
1798 @param[in] FileName Filename string.
1799 @param[in] FileExtension Semi-colon delimeted list of possible extensions.
1800
1801 @retval NULL The file was not found.
1802 @retval !NULL The path to the file.
1803 **/
1804 CHAR16 *
1805 EFIAPI
1806 ShellFindFilePathEx (
1807 IN CONST CHAR16 *FileName,
1808 IN CONST CHAR16 *FileExtension
1809 )
1810 {
1811 CHAR16 *TestPath;
1812 CHAR16 *RetVal;
1813 CONST CHAR16 *ExtensionWalker;
1814 UINTN Size;
1815 CHAR16 *TempChar;
1816 CHAR16 *TempChar2;
1817
1818 ASSERT(FileName != NULL);
1819 if (FileExtension == NULL) {
1820 return (ShellFindFilePath(FileName));
1821 }
1822 RetVal = ShellFindFilePath(FileName);
1823 if (RetVal != NULL) {
1824 return (RetVal);
1825 }
1826 Size = StrSize(FileName);
1827 Size += StrSize(FileExtension);
1828 TestPath = AllocateZeroPool(Size);
1829 if (TestPath == NULL) {
1830 return (NULL);
1831 }
1832 for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){
1833 StrCpyS(TestPath, Size/sizeof(CHAR16), FileName);
1834 if (ExtensionWalker != NULL) {
1835 StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker);
1836 }
1837 TempChar = StrStr(TestPath, L";");
1838 if (TempChar != NULL) {
1839 *TempChar = CHAR_NULL;
1840 }
1841 RetVal = ShellFindFilePath(TestPath);
1842 if (RetVal != NULL) {
1843 break;
1844 }
1845 ASSERT(ExtensionWalker != NULL);
1846 TempChar2 = StrStr(ExtensionWalker, L";");
1847 }
1848 FreePool(TestPath);
1849 return (RetVal);
1850 }
1851
1852 typedef struct {
1853 LIST_ENTRY Link;
1854 CHAR16 *Name;
1855 SHELL_PARAM_TYPE Type;
1856 CHAR16 *Value;
1857 UINTN OriginalPosition;
1858 } SHELL_PARAM_PACKAGE;
1859
1860 /**
1861 Checks the list of valid arguments and returns TRUE if the item was found. If the
1862 return value is TRUE then the type parameter is set also.
1863
1864 if CheckList is NULL then ASSERT();
1865 if Name is NULL then ASSERT();
1866 if Type is NULL then ASSERT();
1867
1868 @param Name pointer to Name of parameter found
1869 @param CheckList List to check against
1870 @param Type pointer to type of parameter if it was found
1871
1872 @retval TRUE the Parameter was found. Type is valid.
1873 @retval FALSE the Parameter was not found. Type is not valid.
1874 **/
1875 BOOLEAN
1876 EFIAPI
1877 InternalIsOnCheckList (
1878 IN CONST CHAR16 *Name,
1879 IN CONST SHELL_PARAM_ITEM *CheckList,
1880 OUT SHELL_PARAM_TYPE *Type
1881 )
1882 {
1883 SHELL_PARAM_ITEM *TempListItem;
1884 CHAR16 *TempString;
1885
1886 //
1887 // ASSERT that all 3 pointer parameters aren't NULL
1888 //
1889 ASSERT(CheckList != NULL);
1890 ASSERT(Type != NULL);
1891 ASSERT(Name != NULL);
1892
1893 //
1894 // question mark and page break mode are always supported
1895 //
1896 if ((StrCmp(Name, L"-?") == 0) ||
1897 (StrCmp(Name, L"-b") == 0)
1898 ) {
1899 *Type = TypeFlag;
1900 return (TRUE);
1901 }
1902
1903 //
1904 // Enumerate through the list
1905 //
1906 for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) {
1907 //
1908 // If the Type is TypeStart only check the first characters of the passed in param
1909 // If it matches set the type and return TRUE
1910 //
1911 if (TempListItem->Type == TypeStart) {
1912 if (StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) {
1913 *Type = TempListItem->Type;
1914 return (TRUE);
1915 }
1916 TempString = NULL;
1917 TempString = StrnCatGrow(&TempString, NULL, Name, StrLen(TempListItem->Name));
1918 if (TempString != NULL) {
1919 if (StringNoCaseCompare(&TempString, &TempListItem->Name) == 0) {
1920 *Type = TempListItem->Type;
1921 FreePool(TempString);
1922 return (TRUE);
1923 }
1924 FreePool(TempString);
1925 }
1926 } else if (StringNoCaseCompare(&Name, &TempListItem->Name) == 0) {
1927 *Type = TempListItem->Type;
1928 return (TRUE);
1929 }
1930 }
1931
1932 return (FALSE);
1933 }
1934 /**
1935 Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'
1936
1937 @param[in] Name pointer to Name of parameter found
1938 @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.
1939 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
1940
1941 @retval TRUE the Parameter is a flag.
1942 @retval FALSE the Parameter not a flag.
1943 **/
1944 BOOLEAN
1945 EFIAPI
1946 InternalIsFlag (
1947 IN CONST CHAR16 *Name,
1948 IN CONST BOOLEAN AlwaysAllowNumbers,
1949 IN CONST BOOLEAN TimeNumbers
1950 )
1951 {
1952 //
1953 // ASSERT that Name isn't NULL
1954 //
1955 ASSERT(Name != NULL);
1956
1957 //
1958 // If we accept numbers then dont return TRUE. (they will be values)
1959 //
1960 if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {
1961 return (FALSE);
1962 }
1963
1964 //
1965 // If the Name has a /, +, or - as the first character return TRUE
1966 //
1967 if ((Name[0] == L'/') ||
1968 (Name[0] == L'-') ||
1969 (Name[0] == L'+')
1970 ) {
1971 return (TRUE);
1972 }
1973 return (FALSE);
1974 }
1975
1976 /**
1977 Checks the command line arguments passed against the list of valid ones.
1978
1979 If no initialization is required, then return RETURN_SUCCESS.
1980
1981 @param[in] CheckList pointer to list of parameters to check
1982 @param[out] CheckPackage pointer to pointer to list checked values
1983 @param[out] ProblemParam optional pointer to pointer to unicode string for
1984 the paramater that caused failure. If used then the
1985 caller is responsible for freeing the memory.
1986 @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter
1987 @param[in] Argv pointer to array of parameters
1988 @param[in] Argc Count of parameters in Argv
1989 @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.
1990
1991 @retval EFI_SUCCESS The operation completed sucessfully.
1992 @retval EFI_OUT_OF_RESOURCES A memory allocation failed
1993 @retval EFI_INVALID_PARAMETER A parameter was invalid
1994 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was
1995 duplicated. the duplicated command line argument
1996 was returned in ProblemParam if provided.
1997 @retval EFI_NOT_FOUND a argument required a value that was missing.
1998 the invalid command line argument was returned in
1999 ProblemParam if provided.
2000 **/
2001 EFI_STATUS
2002 EFIAPI
2003 InternalCommandLineParse (
2004 IN CONST SHELL_PARAM_ITEM *CheckList,
2005 OUT LIST_ENTRY **CheckPackage,
2006 OUT CHAR16 **ProblemParam OPTIONAL,
2007 IN BOOLEAN AutoPageBreak,
2008 IN CONST CHAR16 **Argv,
2009 IN UINTN Argc,
2010 IN BOOLEAN AlwaysAllowNumbers
2011 )
2012 {
2013 UINTN LoopCounter;
2014 SHELL_PARAM_TYPE CurrentItemType;
2015 SHELL_PARAM_PACKAGE *CurrentItemPackage;
2016 UINTN GetItemValue;
2017 UINTN ValueSize;
2018 UINTN Count;
2019 CONST CHAR16 *TempPointer;
2020 UINTN CurrentValueSize;
2021
2022 CurrentItemPackage = NULL;
2023 GetItemValue = 0;
2024 ValueSize = 0;
2025 Count = 0;
2026
2027 //
2028 // If there is only 1 item we dont need to do anything
2029 //
2030 if (Argc < 1) {
2031 *CheckPackage = NULL;
2032 return (EFI_SUCCESS);
2033 }
2034
2035 //
2036 // ASSERTs
2037 //
2038 ASSERT(CheckList != NULL);
2039 ASSERT(Argv != NULL);
2040
2041 //
2042 // initialize the linked list
2043 //
2044 *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY));
2045 if (*CheckPackage == NULL) {
2046 return (EFI_OUT_OF_RESOURCES);
2047 }
2048
2049 InitializeListHead(*CheckPackage);
2050
2051 //
2052 // loop through each of the arguments
2053 //
2054 for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) {
2055 if (Argv[LoopCounter] == NULL) {
2056 //
2057 // do nothing for NULL argv
2058 //
2059 } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType)) {
2060 //
2061 // We might have leftover if last parameter didnt have optional value
2062 //
2063 if (GetItemValue != 0) {
2064 GetItemValue = 0;
2065 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2066 }
2067 //
2068 // this is a flag
2069 //
2070 CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
2071 if (CurrentItemPackage == NULL) {
2072 ShellCommandLineFreeVarList(*CheckPackage);
2073 *CheckPackage = NULL;
2074 return (EFI_OUT_OF_RESOURCES);
2075 }
2076 CurrentItemPackage->Name = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
2077 if (CurrentItemPackage->Name == NULL) {
2078 ShellCommandLineFreeVarList(*CheckPackage);
2079 *CheckPackage = NULL;
2080 return (EFI_OUT_OF_RESOURCES);
2081 }
2082 CurrentItemPackage->Type = CurrentItemType;
2083 CurrentItemPackage->OriginalPosition = (UINTN)(-1);
2084 CurrentItemPackage->Value = NULL;
2085
2086 //
2087 // Does this flag require a value
2088 //
2089 switch (CurrentItemPackage->Type) {
2090 //
2091 // possibly trigger the next loop(s) to populate the value of this item
2092 //
2093 case TypeValue:
2094 case TypeTimeValue:
2095 GetItemValue = 1;
2096 ValueSize = 0;
2097 break;
2098 case TypeDoubleValue:
2099 GetItemValue = 2;
2100 ValueSize = 0;
2101 break;
2102 case TypeMaxValue:
2103 GetItemValue = (UINTN)(-1);
2104 ValueSize = 0;
2105 break;
2106 default:
2107 //
2108 // this item has no value expected; we are done
2109 //
2110 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2111 ASSERT(GetItemValue == 0);
2112 break;
2113 }
2114 } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {
2115 //
2116 // get the item VALUE for a previous flag
2117 //
2118 CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
2119 CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);
2120 ASSERT(CurrentItemPackage->Value != NULL);
2121 if (ValueSize == 0) {
2122 StrCpyS( CurrentItemPackage->Value,
2123 CurrentValueSize/sizeof(CHAR16),
2124 Argv[LoopCounter]
2125 );
2126 } else {
2127 StrCatS( CurrentItemPackage->Value,
2128 CurrentValueSize/sizeof(CHAR16),
2129 L" "
2130 );
2131 StrCatS( CurrentItemPackage->Value,
2132 CurrentValueSize/sizeof(CHAR16),
2133 Argv[LoopCounter]
2134 );
2135 }
2136 ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);
2137
2138 GetItemValue--;
2139 if (GetItemValue == 0) {
2140 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2141 }
2142 } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){
2143 //
2144 // add this one as a non-flag
2145 //
2146
2147 TempPointer = Argv[LoopCounter];
2148 if ((*TempPointer == L'^' && *(TempPointer+1) == L'-')
2149 || (*TempPointer == L'^' && *(TempPointer+1) == L'/')
2150 || (*TempPointer == L'^' && *(TempPointer+1) == L'+')
2151 ){
2152 TempPointer++;
2153 }
2154 CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));
2155 if (CurrentItemPackage == NULL) {
2156 ShellCommandLineFreeVarList(*CheckPackage);
2157 *CheckPackage = NULL;
2158 return (EFI_OUT_OF_RESOURCES);
2159 }
2160 CurrentItemPackage->Name = NULL;
2161 CurrentItemPackage->Type = TypePosition;
2162 CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);
2163 if (CurrentItemPackage->Value == NULL) {
2164 ShellCommandLineFreeVarList(*CheckPackage);
2165 *CheckPackage = NULL;
2166 return (EFI_OUT_OF_RESOURCES);
2167 }
2168 CurrentItemPackage->OriginalPosition = Count++;
2169 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2170 } else {
2171 //
2172 // this was a non-recognised flag... error!
2173 //
2174 if (ProblemParam != NULL) {
2175 *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);
2176 }
2177 ShellCommandLineFreeVarList(*CheckPackage);
2178 *CheckPackage = NULL;
2179 return (EFI_VOLUME_CORRUPTED);
2180 }
2181 }
2182 if (GetItemValue != 0) {
2183 GetItemValue = 0;
2184 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);
2185 }
2186 //
2187 // support for AutoPageBreak
2188 //
2189 if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) {
2190 ShellSetPageBreakMode(TRUE);
2191 }
2192 return (EFI_SUCCESS);
2193 }
2194
2195 /**
2196 Checks the command line arguments passed against the list of valid ones.
2197 Optionally removes NULL values first.
2198
2199 If no initialization is required, then return RETURN_SUCCESS.
2200
2201 @param[in] CheckList The pointer to list of parameters to check.
2202 @param[out] CheckPackage The package of checked values.
2203 @param[out] ProblemParam Optional pointer to pointer to unicode string for
2204 the paramater that caused failure.
2205 @param[in] AutoPageBreak Will automatically set PageBreakEnabled.
2206 @param[in] AlwaysAllowNumbers Will never fail for number based flags.
2207
2208 @retval EFI_SUCCESS The operation completed sucessfully.
2209 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2210 @retval EFI_INVALID_PARAMETER A parameter was invalid.
2211 @retval EFI_VOLUME_CORRUPTED The command line was corrupt.
2212 @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One
2213 of the command line arguments was returned in
2214 ProblemParam if provided.
2215 @retval EFI_NOT_FOUND A argument required a value that was missing.
2216 The invalid command line argument was returned in
2217 ProblemParam if provided.
2218 **/
2219 EFI_STATUS
2220 EFIAPI
2221 ShellCommandLineParseEx (
2222 IN CONST SHELL_PARAM_ITEM *CheckList,
2223 OUT LIST_ENTRY **CheckPackage,
2224 OUT CHAR16 **ProblemParam OPTIONAL,
2225 IN BOOLEAN AutoPageBreak,
2226 IN BOOLEAN AlwaysAllowNumbers
2227 )
2228 {
2229 //
2230 // ASSERT that CheckList and CheckPackage aren't NULL
2231 //
2232 ASSERT(CheckList != NULL);
2233 ASSERT(CheckPackage != NULL);
2234
2235 //
2236 // Check for UEFI Shell 2.0 protocols
2237 //
2238 if (gEfiShellParametersProtocol != NULL) {
2239 return (InternalCommandLineParse(CheckList,
2240 CheckPackage,
2241 ProblemParam,
2242 AutoPageBreak,
2243 (CONST CHAR16**) gEfiShellParametersProtocol->Argv,
2244 gEfiShellParametersProtocol->Argc,
2245 AlwaysAllowNumbers));
2246 }
2247
2248 //
2249 // ASSERT That EFI Shell is not required
2250 //
2251 ASSERT (mEfiShellInterface != NULL);
2252 return (InternalCommandLineParse(CheckList,
2253 CheckPackage,
2254 ProblemParam,
2255 AutoPageBreak,
2256 (CONST CHAR16**) mEfiShellInterface->Argv,
2257 mEfiShellInterface->Argc,
2258 AlwaysAllowNumbers));
2259 }
2260
2261 /**
2262 Frees shell variable list that was returned from ShellCommandLineParse.
2263
2264 This function will free all the memory that was used for the CheckPackage
2265 list of postprocessed shell arguments.
2266
2267 this function has no return value.
2268
2269 if CheckPackage is NULL, then return
2270
2271 @param CheckPackage the list to de-allocate
2272 **/
2273 VOID
2274 EFIAPI
2275 ShellCommandLineFreeVarList (
2276 IN LIST_ENTRY *CheckPackage
2277 )
2278 {
2279 LIST_ENTRY *Node;
2280
2281 //
2282 // check for CheckPackage == NULL
2283 //
2284 if (CheckPackage == NULL) {
2285 return;
2286 }
2287
2288 //
2289 // for each node in the list
2290 //
2291 for ( Node = GetFirstNode(CheckPackage)
2292 ; !IsListEmpty(CheckPackage)
2293 ; Node = GetFirstNode(CheckPackage)
2294 ){
2295 //
2296 // Remove it from the list
2297 //
2298 RemoveEntryList(Node);
2299
2300 //
2301 // if it has a name free the name
2302 //
2303 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2304 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name);
2305 }
2306
2307 //
2308 // if it has a value free the value
2309 //
2310 if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) {
2311 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value);
2312 }
2313
2314 //
2315 // free the node structure
2316 //
2317 FreePool((SHELL_PARAM_PACKAGE*)Node);
2318 }
2319 //
2320 // free the list head node
2321 //
2322 FreePool(CheckPackage);
2323 }
2324 /**
2325 Checks for presence of a flag parameter
2326
2327 flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key
2328
2329 if CheckPackage is NULL then return FALSE.
2330 if KeyString is NULL then ASSERT()
2331
2332 @param CheckPackage The package of parsed command line arguments
2333 @param KeyString the Key of the command line argument to check for
2334
2335 @retval TRUE the flag is on the command line
2336 @retval FALSE the flag is not on the command line
2337 **/
2338 BOOLEAN
2339 EFIAPI
2340 ShellCommandLineGetFlag (
2341 IN CONST LIST_ENTRY * CONST CheckPackage,
2342 IN CONST CHAR16 * CONST KeyString
2343 )
2344 {
2345 LIST_ENTRY *Node;
2346 CHAR16 *TempString;
2347
2348 //
2349 // return FALSE for no package or KeyString is NULL
2350 //
2351 if (CheckPackage == NULL || KeyString == NULL) {
2352 return (FALSE);
2353 }
2354
2355 //
2356 // enumerate through the list of parametrs
2357 //
2358 for ( Node = GetFirstNode(CheckPackage)
2359 ; !IsNull (CheckPackage, Node)
2360 ; Node = GetNextNode(CheckPackage, Node)
2361 ){
2362 //
2363 // If the Name matches, return TRUE (and there may be NULL name)
2364 //
2365 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2366 //
2367 // If Type is TypeStart then only compare the begining of the strings
2368 //
2369 if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {
2370 if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {
2371 return (TRUE);
2372 }
2373 TempString = NULL;
2374 TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));
2375 if (TempString != NULL) {
2376 if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2377 FreePool(TempString);
2378 return (TRUE);
2379 }
2380 FreePool(TempString);
2381 }
2382 } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2383 return (TRUE);
2384 }
2385 }
2386 }
2387 return (FALSE);
2388 }
2389 /**
2390 Returns value from command line argument.
2391
2392 Value parameters are in the form of "-<Key> value" or "/<Key> value".
2393
2394 If CheckPackage is NULL, then return NULL.
2395
2396 @param[in] CheckPackage The package of parsed command line arguments.
2397 @param[in] KeyString The Key of the command line argument to check for.
2398
2399 @retval NULL The flag is not on the command line.
2400 @retval !=NULL The pointer to unicode string of the value.
2401 **/
2402 CONST CHAR16*
2403 EFIAPI
2404 ShellCommandLineGetValue (
2405 IN CONST LIST_ENTRY *CheckPackage,
2406 IN CHAR16 *KeyString
2407 )
2408 {
2409 LIST_ENTRY *Node;
2410 CHAR16 *TempString;
2411
2412 //
2413 // return NULL for no package or KeyString is NULL
2414 //
2415 if (CheckPackage == NULL || KeyString == NULL) {
2416 return (NULL);
2417 }
2418
2419 //
2420 // enumerate through the list of parametrs
2421 //
2422 for ( Node = GetFirstNode(CheckPackage)
2423 ; !IsNull (CheckPackage, Node)
2424 ; Node = GetNextNode(CheckPackage, Node)
2425 ){
2426 //
2427 // If the Name matches, return TRUE (and there may be NULL name)
2428 //
2429 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {
2430 //
2431 // If Type is TypeStart then only compare the begining of the strings
2432 //
2433 if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {
2434 if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {
2435 return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));
2436 }
2437 TempString = NULL;
2438 TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));
2439 if (TempString != NULL) {
2440 if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2441 FreePool(TempString);
2442 return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));
2443 }
2444 FreePool(TempString);
2445 }
2446 } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {
2447 return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2448 }
2449 }
2450 }
2451 return (NULL);
2452 }
2453
2454 /**
2455 Returns raw value from command line argument.
2456
2457 Raw value parameters are in the form of "value" in a specific position in the list.
2458
2459 If CheckPackage is NULL, then return NULL.
2460
2461 @param[in] CheckPackage The package of parsed command line arguments.
2462 @param[in] Position The position of the value.
2463
2464 @retval NULL The flag is not on the command line.
2465 @retval !=NULL The pointer to unicode string of the value.
2466 **/
2467 CONST CHAR16*
2468 EFIAPI
2469 ShellCommandLineGetRawValue (
2470 IN CONST LIST_ENTRY * CONST CheckPackage,
2471 IN UINTN Position
2472 )
2473 {
2474 LIST_ENTRY *Node;
2475
2476 //
2477 // check for CheckPackage == NULL
2478 //
2479 if (CheckPackage == NULL) {
2480 return (NULL);
2481 }
2482
2483 //
2484 // enumerate through the list of parametrs
2485 //
2486 for ( Node = GetFirstNode(CheckPackage)
2487 ; !IsNull (CheckPackage, Node)
2488 ; Node = GetNextNode(CheckPackage, Node)
2489 ){
2490 //
2491 // If the position matches, return the value
2492 //
2493 if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) {
2494 return (((SHELL_PARAM_PACKAGE*)Node)->Value);
2495 }
2496 }
2497 return (NULL);
2498 }
2499
2500 /**
2501 returns the number of command line value parameters that were parsed.
2502
2503 this will not include flags.
2504
2505 @param[in] CheckPackage The package of parsed command line arguments.
2506
2507 @retval (UINTN)-1 No parsing has ocurred
2508 @return other The number of value parameters found
2509 **/
2510 UINTN
2511 EFIAPI
2512 ShellCommandLineGetCount(
2513 IN CONST LIST_ENTRY *CheckPackage
2514 )
2515 {
2516 LIST_ENTRY *Node1;
2517 UINTN Count;
2518
2519 if (CheckPackage == NULL) {
2520 return (0);
2521 }
2522 for ( Node1 = GetFirstNode(CheckPackage), Count = 0
2523 ; !IsNull (CheckPackage, Node1)
2524 ; Node1 = GetNextNode(CheckPackage, Node1)
2525 ){
2526 if (((SHELL_PARAM_PACKAGE*)Node1)->Name == NULL) {
2527 Count++;
2528 }
2529 }
2530 return (Count);
2531 }
2532
2533 /**
2534 Determines if a parameter is duplicated.
2535
2536 If Param is not NULL then it will point to a callee allocated string buffer
2537 with the parameter value if a duplicate is found.
2538
2539 If CheckPackage is NULL, then ASSERT.
2540
2541 @param[in] CheckPackage The package of parsed command line arguments.
2542 @param[out] Param Upon finding one, a pointer to the duplicated parameter.
2543
2544 @retval EFI_SUCCESS No parameters were duplicated.
2545 @retval EFI_DEVICE_ERROR A duplicate was found.
2546 **/
2547 EFI_STATUS
2548 EFIAPI
2549 ShellCommandLineCheckDuplicate (
2550 IN CONST LIST_ENTRY *CheckPackage,
2551 OUT CHAR16 **Param
2552 )
2553 {
2554 LIST_ENTRY *Node1;
2555 LIST_ENTRY *Node2;
2556
2557 ASSERT(CheckPackage != NULL);
2558
2559 for ( Node1 = GetFirstNode(CheckPackage)
2560 ; !IsNull (CheckPackage, Node1)
2561 ; Node1 = GetNextNode(CheckPackage, Node1)
2562 ){
2563 for ( Node2 = GetNextNode(CheckPackage, Node1)
2564 ; !IsNull (CheckPackage, Node2)
2565 ; Node2 = GetNextNode(CheckPackage, Node2)
2566 ){
2567 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) {
2568 if (Param != NULL) {
2569 *Param = NULL;
2570 *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0);
2571 }
2572 return (EFI_DEVICE_ERROR);
2573 }
2574 }
2575 }
2576 return (EFI_SUCCESS);
2577 }
2578
2579 /**
2580 This is a find and replace function. Upon successful return the NewString is a copy of
2581 SourceString with each instance of FindTarget replaced with ReplaceWith.
2582
2583 If SourceString and NewString overlap the behavior is undefined.
2584
2585 If the string would grow bigger than NewSize it will halt and return error.
2586
2587 @param[in] SourceString The string with source buffer.
2588 @param[in, out] NewString The string with resultant buffer.
2589 @param[in] NewSize The size in bytes of NewString.
2590 @param[in] FindTarget The string to look for.
2591 @param[in] ReplaceWith The string to replace FindTarget with.
2592 @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'
2593 immediately before it.
2594 @param[in] ParameterReplacing If TRUE will add "" around items with spaces.
2595
2596 @retval EFI_INVALID_PARAMETER SourceString was NULL.
2597 @retval EFI_INVALID_PARAMETER NewString was NULL.
2598 @retval EFI_INVALID_PARAMETER FindTarget was NULL.
2599 @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.
2600 @retval EFI_INVALID_PARAMETER FindTarget had length < 1.
2601 @retval EFI_INVALID_PARAMETER SourceString had length < 1.
2602 @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold
2603 the new string (truncation occurred).
2604 @retval EFI_SUCCESS The string was successfully copied with replacement.
2605 **/
2606 EFI_STATUS
2607 EFIAPI
2608 ShellCopySearchAndReplace(
2609 IN CHAR16 CONST *SourceString,
2610 IN OUT CHAR16 *NewString,
2611 IN UINTN NewSize,
2612 IN CONST CHAR16 *FindTarget,
2613 IN CONST CHAR16 *ReplaceWith,
2614 IN CONST BOOLEAN SkipPreCarrot,
2615 IN CONST BOOLEAN ParameterReplacing
2616 )
2617 {
2618 UINTN Size;
2619 CHAR16 *Replace;
2620
2621 if ( (SourceString == NULL)
2622 || (NewString == NULL)
2623 || (FindTarget == NULL)
2624 || (ReplaceWith == NULL)
2625 || (StrLen(FindTarget) < 1)
2626 || (StrLen(SourceString) < 1)
2627 ){
2628 return (EFI_INVALID_PARAMETER);
2629 }
2630 Replace = NULL;
2631 if (StrStr(ReplaceWith, L" ") == NULL || !ParameterReplacing) {
2632 Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0);
2633 } else {
2634 Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16));
2635 if (Replace != NULL) {
2636 UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith);
2637 }
2638 }
2639 if (Replace == NULL) {
2640 return (EFI_OUT_OF_RESOURCES);
2641 }
2642 NewString = ZeroMem(NewString, NewSize);
2643 while (*SourceString != CHAR_NULL) {
2644 //
2645 // if we find the FindTarget and either Skip == FALSE or Skip and we
2646 // dont have a carrot do a replace...
2647 //
2648 if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0
2649 && ((SkipPreCarrot && *(SourceString-1) != L'^') || !SkipPreCarrot)
2650 ){
2651 SourceString += StrLen(FindTarget);
2652 Size = StrSize(NewString);
2653 if ((Size + (StrLen(Replace)*sizeof(CHAR16))) > NewSize) {
2654 FreePool(Replace);
2655 return (EFI_BUFFER_TOO_SMALL);
2656 }
2657 StrCatS(NewString, NewSize/sizeof(CHAR16), Replace);
2658 } else {
2659 Size = StrSize(NewString);
2660 if (Size + sizeof(CHAR16) > NewSize) {
2661 FreePool(Replace);
2662 return (EFI_BUFFER_TOO_SMALL);
2663 }
2664 StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1);
2665 SourceString++;
2666 }
2667 }
2668 FreePool(Replace);
2669 return (EFI_SUCCESS);
2670 }
2671
2672 /**
2673 Internal worker function to output a string.
2674
2675 This function will output a string to the correct StdOut.
2676
2677 @param[in] String The string to print out.
2678
2679 @retval EFI_SUCCESS The operation was sucessful.
2680 @retval !EFI_SUCCESS The operation failed.
2681 **/
2682 EFI_STATUS
2683 EFIAPI
2684 InternalPrintTo (
2685 IN CONST CHAR16 *String
2686 )
2687 {
2688 UINTN Size;
2689 Size = StrSize(String) - sizeof(CHAR16);
2690 if (Size == 0) {
2691 return (EFI_SUCCESS);
2692 }
2693 if (gEfiShellParametersProtocol != NULL) {
2694 return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));
2695 }
2696 if (mEfiShellInterface != NULL) {
2697 if (mEfiShellInterface->RedirArgc == 0) {
2698 //
2699 // Divide in half for old shell. Must be string length not size.
2700 //
2701 Size /=2; // Divide in half only when no redirection.
2702 }
2703 return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String));
2704 }
2705 ASSERT(FALSE);
2706 return (EFI_UNSUPPORTED);
2707 }
2708
2709 /**
2710 Print at a specific location on the screen.
2711
2712 This function will move the cursor to a given screen location and print the specified string
2713
2714 If -1 is specified for either the Row or Col the current screen location for BOTH
2715 will be used.
2716
2717 if either Row or Col is out of range for the current console, then ASSERT
2718 if Format is NULL, then ASSERT
2719
2720 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2721 the following additional flags:
2722 %N - Set output attribute to normal
2723 %H - Set output attribute to highlight
2724 %E - Set output attribute to error
2725 %B - Set output attribute to blue color
2726 %V - Set output attribute to green color
2727
2728 Note: The background color is controlled by the shell command cls.
2729
2730 @param[in] Col the column to print at
2731 @param[in] Row the row to print at
2732 @param[in] Format the format string
2733 @param[in] Marker the marker for the variable argument list
2734
2735 @return EFI_SUCCESS The operation was successful.
2736 @return EFI_DEVICE_ERROR The console device reported an error.
2737 **/
2738 EFI_STATUS
2739 EFIAPI
2740 InternalShellPrintWorker(
2741 IN INT32 Col OPTIONAL,
2742 IN INT32 Row OPTIONAL,
2743 IN CONST CHAR16 *Format,
2744 IN VA_LIST Marker
2745 )
2746 {
2747 EFI_STATUS Status;
2748 CHAR16 *ResumeLocation;
2749 CHAR16 *FormatWalker;
2750 UINTN OriginalAttribute;
2751 CHAR16 *mPostReplaceFormat;
2752 CHAR16 *mPostReplaceFormat2;
2753
2754 mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));
2755 mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));
2756
2757 if (mPostReplaceFormat == NULL || mPostReplaceFormat2 == NULL) {
2758 SHELL_FREE_NON_NULL(mPostReplaceFormat);
2759 SHELL_FREE_NON_NULL(mPostReplaceFormat2);
2760 return (EFI_OUT_OF_RESOURCES);
2761 }
2762
2763 Status = EFI_SUCCESS;
2764 OriginalAttribute = gST->ConOut->Mode->Attribute;
2765
2766 //
2767 // Back and forth each time fixing up 1 of our flags...
2768 //
2769 Status = ShellCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE);
2770 ASSERT_EFI_ERROR(Status);
2771 Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE);
2772 ASSERT_EFI_ERROR(Status);
2773 Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE);
2774 ASSERT_EFI_ERROR(Status);
2775 Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE);
2776 ASSERT_EFI_ERROR(Status);
2777 Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE);
2778 ASSERT_EFI_ERROR(Status);
2779
2780 //
2781 // Use the last buffer from replacing to print from...
2782 //
2783 UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);
2784
2785 if (Col != -1 && Row != -1) {
2786 Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row);
2787 }
2788
2789 FormatWalker = mPostReplaceFormat2;
2790 while (*FormatWalker != CHAR_NULL) {
2791 //
2792 // Find the next attribute change request
2793 //
2794 ResumeLocation = StrStr(FormatWalker, L"%");
2795 if (ResumeLocation != NULL) {
2796 *ResumeLocation = CHAR_NULL;
2797 }
2798 //
2799 // print the current FormatWalker string
2800 //
2801 if (StrLen(FormatWalker)>0) {
2802 Status = InternalPrintTo(FormatWalker);
2803 if (EFI_ERROR(Status)) {
2804 break;
2805 }
2806 }
2807
2808 //
2809 // update the attribute
2810 //
2811 if (ResumeLocation != NULL) {
2812 if (*(ResumeLocation-1) == L'^') {
2813 //
2814 // Move cursor back 1 position to overwrite the ^
2815 //
2816 gST->ConOut->SetCursorPosition(gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);
2817
2818 //
2819 // Print a simple '%' symbol
2820 //
2821 Status = InternalPrintTo(L"%");
2822 ResumeLocation = ResumeLocation - 1;
2823 } else {
2824 switch (*(ResumeLocation+1)) {
2825 case (L'N'):
2826 gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);
2827 break;
2828 case (L'E'):
2829 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2830 break;
2831 case (L'H'):
2832 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2833 break;
2834 case (L'B'):
2835 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_BLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2836 break;
2837 case (L'V'):
2838 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_GREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));
2839 break;
2840 default:
2841 //
2842 // Print a simple '%' symbol
2843 //
2844 Status = InternalPrintTo(L"%");
2845 if (EFI_ERROR(Status)) {
2846 break;
2847 }
2848 ResumeLocation = ResumeLocation - 1;
2849 break;
2850 }
2851 }
2852 } else {
2853 //
2854 // reset to normal now...
2855 //
2856 break;
2857 }
2858
2859 //
2860 // update FormatWalker to Resume + 2 (skip the % and the indicator)
2861 //
2862 FormatWalker = ResumeLocation + 2;
2863 }
2864
2865 gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);
2866
2867 SHELL_FREE_NON_NULL(mPostReplaceFormat);
2868 SHELL_FREE_NON_NULL(mPostReplaceFormat2);
2869 return (Status);
2870 }
2871
2872 /**
2873 Print at a specific location on the screen.
2874
2875 This function will move the cursor to a given screen location and print the specified string.
2876
2877 If -1 is specified for either the Row or Col the current screen location for BOTH
2878 will be used.
2879
2880 If either Row or Col is out of range for the current console, then ASSERT.
2881 If Format is NULL, then ASSERT.
2882
2883 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2884 the following additional flags:
2885 %N - Set output attribute to normal
2886 %H - Set output attribute to highlight
2887 %E - Set output attribute to error
2888 %B - Set output attribute to blue color
2889 %V - Set output attribute to green color
2890
2891 Note: The background color is controlled by the shell command cls.
2892
2893 @param[in] Col the column to print at
2894 @param[in] Row the row to print at
2895 @param[in] Format the format string
2896 @param[in] ... The variable argument list.
2897
2898 @return EFI_SUCCESS The printing was successful.
2899 @return EFI_DEVICE_ERROR The console device reported an error.
2900 **/
2901 EFI_STATUS
2902 EFIAPI
2903 ShellPrintEx(
2904 IN INT32 Col OPTIONAL,
2905 IN INT32 Row OPTIONAL,
2906 IN CONST CHAR16 *Format,
2907 ...
2908 )
2909 {
2910 VA_LIST Marker;
2911 EFI_STATUS RetVal;
2912 if (Format == NULL) {
2913 return (EFI_INVALID_PARAMETER);
2914 }
2915 VA_START (Marker, Format);
2916 RetVal = InternalShellPrintWorker(Col, Row, Format, Marker);
2917 VA_END(Marker);
2918 return(RetVal);
2919 }
2920
2921 /**
2922 Print at a specific location on the screen.
2923
2924 This function will move the cursor to a given screen location and print the specified string.
2925
2926 If -1 is specified for either the Row or Col the current screen location for BOTH
2927 will be used.
2928
2929 If either Row or Col is out of range for the current console, then ASSERT.
2930 If Format is NULL, then ASSERT.
2931
2932 In addition to the standard %-based flags as supported by UefiLib Print() this supports
2933 the following additional flags:
2934 %N - Set output attribute to normal.
2935 %H - Set output attribute to highlight.
2936 %E - Set output attribute to error.
2937 %B - Set output attribute to blue color.
2938 %V - Set output attribute to green color.
2939
2940 Note: The background color is controlled by the shell command cls.
2941
2942 @param[in] Col The column to print at.
2943 @param[in] Row The row to print at.
2944 @param[in] Language The language of the string to retrieve. If this parameter
2945 is NULL, then the current platform language is used.
2946 @param[in] HiiFormatStringId The format string Id for getting from Hii.
2947 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
2948 @param[in] ... The variable argument list.
2949
2950 @return EFI_SUCCESS The printing was successful.
2951 @return EFI_DEVICE_ERROR The console device reported an error.
2952 **/
2953 EFI_STATUS
2954 EFIAPI
2955 ShellPrintHiiEx(
2956 IN INT32 Col OPTIONAL,
2957 IN INT32 Row OPTIONAL,
2958 IN CONST CHAR8 *Language OPTIONAL,
2959 IN CONST EFI_STRING_ID HiiFormatStringId,
2960 IN CONST EFI_HANDLE HiiFormatHandle,
2961 ...
2962 )
2963 {
2964 VA_LIST Marker;
2965 CHAR16 *HiiFormatString;
2966 EFI_STATUS RetVal;
2967
2968 VA_START (Marker, HiiFormatHandle);
2969 HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);
2970 ASSERT(HiiFormatString != NULL);
2971
2972 RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);
2973
2974 SHELL_FREE_NON_NULL(HiiFormatString);
2975 VA_END(Marker);
2976
2977 return (RetVal);
2978 }
2979
2980 /**
2981 Function to determine if a given filename represents a file or a directory.
2982
2983 @param[in] DirName Path to directory to test.
2984
2985 @retval EFI_SUCCESS The Path represents a directory
2986 @retval EFI_NOT_FOUND The Path does not represent a directory
2987 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
2988 @return The path failed to open
2989 **/
2990 EFI_STATUS
2991 EFIAPI
2992 ShellIsDirectory(
2993 IN CONST CHAR16 *DirName
2994 )
2995 {
2996 EFI_STATUS Status;
2997 SHELL_FILE_HANDLE Handle;
2998 CHAR16 *TempLocation;
2999 CHAR16 *TempLocation2;
3000
3001 ASSERT(DirName != NULL);
3002
3003 Handle = NULL;
3004 TempLocation = NULL;
3005
3006 Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);
3007 if (EFI_ERROR(Status)) {
3008 //
3009 // try good logic first.
3010 //
3011 if (gEfiShellProtocol != NULL) {
3012 TempLocation = StrnCatGrow(&TempLocation, NULL, DirName, 0);
3013 if (TempLocation == NULL) {
3014 ShellCloseFile(&Handle);
3015 return (EFI_OUT_OF_RESOURCES);
3016 }
3017 TempLocation2 = StrStr(TempLocation, L":");
3018 if (TempLocation2 != NULL && StrLen(StrStr(TempLocation, L":")) == 2) {
3019 *(TempLocation2+1) = CHAR_NULL;
3020 }
3021 if (gEfiShellProtocol->GetDevicePathFromMap(TempLocation) != NULL) {
3022 FreePool(TempLocation);
3023 return (EFI_SUCCESS);
3024 }
3025 FreePool(TempLocation);
3026 } else {
3027 //
3028 // probably a map name?!?!!?
3029 //
3030 TempLocation = StrStr(DirName, L"\\");
3031 if (TempLocation != NULL && *(TempLocation+1) == CHAR_NULL) {
3032 return (EFI_SUCCESS);
3033 }
3034 }
3035 return (Status);
3036 }
3037
3038 if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {
3039 ShellCloseFile(&Handle);
3040 return (EFI_SUCCESS);
3041 }
3042 ShellCloseFile(&Handle);
3043 return (EFI_NOT_FOUND);
3044 }
3045
3046 /**
3047 Function to determine if a given filename represents a file.
3048
3049 @param[in] Name Path to file to test.
3050
3051 @retval EFI_SUCCESS The Path represents a file.
3052 @retval EFI_NOT_FOUND The Path does not represent a file.
3053 @retval other The path failed to open.
3054 **/
3055 EFI_STATUS
3056 EFIAPI
3057 ShellIsFile(
3058 IN CONST CHAR16 *Name
3059 )
3060 {
3061 EFI_STATUS Status;
3062 SHELL_FILE_HANDLE Handle;
3063
3064 ASSERT(Name != NULL);
3065
3066 Handle = NULL;
3067
3068 Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0);
3069 if (EFI_ERROR(Status)) {
3070 return (Status);
3071 }
3072
3073 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {
3074 ShellCloseFile(&Handle);
3075 return (EFI_SUCCESS);
3076 }
3077 ShellCloseFile(&Handle);
3078 return (EFI_NOT_FOUND);
3079 }
3080
3081 /**
3082 Function to determine if a given filename represents a file.
3083
3084 This will search the CWD and then the Path.
3085
3086 If Name is NULL, then ASSERT.
3087
3088 @param[in] Name Path to file to test.
3089
3090 @retval EFI_SUCCESS The Path represents a file.
3091 @retval EFI_NOT_FOUND The Path does not represent a file.
3092 @retval other The path failed to open.
3093 **/
3094 EFI_STATUS
3095 EFIAPI
3096 ShellIsFileInPath(
3097 IN CONST CHAR16 *Name
3098 )
3099 {
3100 CHAR16 *NewName;
3101 EFI_STATUS Status;
3102
3103 if (!EFI_ERROR(ShellIsFile(Name))) {
3104 return (EFI_SUCCESS);
3105 }
3106
3107 NewName = ShellFindFilePath(Name);
3108 if (NewName == NULL) {
3109 return (EFI_NOT_FOUND);
3110 }
3111 Status = ShellIsFile(NewName);
3112 FreePool(NewName);
3113 return (Status);
3114 }
3115
3116 /**
3117 Function return the number converted from a hex representation of a number.
3118
3119 Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid
3120 result. Use ShellConvertStringToUint64 instead.
3121
3122 @param[in] String String representation of a number.
3123
3124 @return The unsigned integer result of the conversion.
3125 @retval (UINTN)(-1) An error occured.
3126 **/
3127 UINTN
3128 EFIAPI
3129 ShellHexStrToUintn(
3130 IN CONST CHAR16 *String
3131 )
3132 {
3133 UINT64 RetVal;
3134
3135 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {
3136 return ((UINTN)RetVal);
3137 }
3138
3139 return ((UINTN)(-1));
3140 }
3141
3142 /**
3143 Function to determine whether a string is decimal or hex representation of a number
3144 and return the number converted from the string. Spaces are always skipped.
3145
3146 @param[in] String String representation of a number
3147
3148 @return the number
3149 @retval (UINTN)(-1) An error ocurred.
3150 **/
3151 UINTN
3152 EFIAPI
3153 ShellStrToUintn(
3154 IN CONST CHAR16 *String
3155 )
3156 {
3157 UINT64 RetVal;
3158 BOOLEAN Hex;
3159
3160 Hex = FALSE;
3161
3162 if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) {
3163 Hex = TRUE;
3164 }
3165
3166 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, Hex, TRUE))) {
3167 return ((UINTN)RetVal);
3168 }
3169 return ((UINTN)(-1));
3170 }
3171
3172 /**
3173 Safely append with automatic string resizing given length of Destination and
3174 desired length of copy from Source.
3175
3176 append the first D characters of Source to the end of Destination, where D is
3177 the lesser of Count and the StrLen() of Source. If appending those D characters
3178 will fit within Destination (whose Size is given as CurrentSize) and
3179 still leave room for a NULL terminator, then those characters are appended,
3180 starting at the original terminating NULL of Destination, and a new terminating
3181 NULL is appended.
3182
3183 If appending D characters onto Destination will result in a overflow of the size
3184 given in CurrentSize the string will be grown such that the copy can be performed
3185 and CurrentSize will be updated to the new size.
3186
3187 If Source is NULL, there is nothing to append, just return the current buffer in
3188 Destination.
3189
3190 if Destination is NULL, then ASSERT()
3191 if Destination's current length (including NULL terminator) is already more then
3192 CurrentSize, then ASSERT()
3193
3194 @param[in, out] Destination The String to append onto
3195 @param[in, out] CurrentSize on call the number of bytes in Destination. On
3196 return possibly the new size (still in bytes). if NULL
3197 then allocate whatever is needed.
3198 @param[in] Source The String to append from
3199 @param[in] Count Maximum number of characters to append. if 0 then
3200 all are appended.
3201
3202 @return Destination return the resultant string.
3203 **/
3204 CHAR16*
3205 EFIAPI
3206 StrnCatGrow (
3207 IN OUT CHAR16 **Destination,
3208 IN OUT UINTN *CurrentSize,
3209 IN CONST CHAR16 *Source,
3210 IN UINTN Count
3211 )
3212 {
3213 UINTN DestinationStartSize;
3214 UINTN NewSize;
3215
3216 //
3217 // ASSERTs
3218 //
3219 ASSERT(Destination != NULL);
3220
3221 //
3222 // If there's nothing to do then just return Destination
3223 //
3224 if (Source == NULL) {
3225 return (*Destination);
3226 }
3227
3228 //
3229 // allow for un-initialized pointers, based on size being 0
3230 //
3231 if (CurrentSize != NULL && *CurrentSize == 0) {
3232 *Destination = NULL;
3233 }
3234
3235 //
3236 // allow for NULL pointers address as Destination
3237 //
3238 if (*Destination != NULL) {
3239 ASSERT(CurrentSize != 0);
3240 DestinationStartSize = StrSize(*Destination);
3241 ASSERT(DestinationStartSize <= *CurrentSize);
3242 } else {
3243 DestinationStartSize = 0;
3244 // ASSERT(*CurrentSize == 0);
3245 }
3246
3247 //
3248 // Append all of Source?
3249 //
3250 if (Count == 0) {
3251 Count = StrLen(Source);
3252 }
3253
3254 //
3255 // Test and grow if required
3256 //
3257 if (CurrentSize != NULL) {
3258 NewSize = *CurrentSize;
3259 if (NewSize < DestinationStartSize + (Count * sizeof(CHAR16))) {
3260 while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {
3261 NewSize += 2 * Count * sizeof(CHAR16);
3262 }
3263 *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
3264 *CurrentSize = NewSize;
3265 }
3266 } else {
3267 NewSize = (Count+1)*sizeof(CHAR16);
3268 *Destination = AllocateZeroPool(NewSize);
3269 }
3270
3271 //
3272 // Now use standard StrnCat on a big enough buffer
3273 //
3274 if (*Destination == NULL) {
3275 return (NULL);
3276 }
3277
3278 StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);
3279 return *Destination;
3280 }
3281
3282 /**
3283 Prompt the user and return the resultant answer to the requestor.
3284
3285 This function will display the requested question on the shell prompt and then
3286 wait for an apropriate answer to be input from the console.
3287
3288 if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue
3289 or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.
3290
3291 if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type
3292 CHAR16*.
3293
3294 In either case *Response must be callee freed if Response was not NULL;
3295
3296 @param Type What type of question is asked. This is used to filter the input
3297 to prevent invalid answers to question.
3298 @param Prompt Pointer to string prompt to use to request input.
3299 @param Response Pointer to Response which will be populated upon return.
3300
3301 @retval EFI_SUCCESS The operation was sucessful.
3302 @retval EFI_UNSUPPORTED The operation is not supported as requested.
3303 @retval EFI_INVALID_PARAMETER A parameter was invalid.
3304 @return other The operation failed.
3305 **/
3306 EFI_STATUS
3307 EFIAPI
3308 ShellPromptForResponse (
3309 IN SHELL_PROMPT_REQUEST_TYPE Type,
3310 IN CHAR16 *Prompt OPTIONAL,
3311 IN OUT VOID **Response OPTIONAL
3312 )
3313 {
3314 EFI_STATUS Status;
3315 EFI_INPUT_KEY Key;
3316 UINTN EventIndex;
3317 SHELL_PROMPT_RESPONSE *Resp;
3318 UINTN Size;
3319 CHAR16 *Buffer;
3320
3321 Status = EFI_UNSUPPORTED;
3322 Resp = NULL;
3323 Buffer = NULL;
3324 Size = 0;
3325 if (Type != ShellPromptResponseTypeFreeform) {
3326 Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE));
3327 if (Resp == NULL) {
3328 return (EFI_OUT_OF_RESOURCES);
3329 }
3330 }
3331
3332 switch(Type) {
3333 case ShellPromptResponseTypeQuitContinue:
3334 if (Prompt != NULL) {
3335 ShellPrintEx(-1, -1, L"%s", Prompt);
3336 }
3337 //
3338 // wait for valid response
3339 //
3340 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3341 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3342 if (EFI_ERROR(Status)) {
3343 break;
3344 }
3345 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3346 if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') {
3347 *Resp = ShellPromptResponseQuit;
3348 } else {
3349 *Resp = ShellPromptResponseContinue;
3350 }
3351 break;
3352 case ShellPromptResponseTypeYesNoCancel:
3353 if (Prompt != NULL) {
3354 ShellPrintEx(-1, -1, L"%s", Prompt);
3355 }
3356 //
3357 // wait for valid response
3358 //
3359 *Resp = ShellPromptResponseMax;
3360 while (*Resp == ShellPromptResponseMax) {
3361 if (ShellGetExecutionBreakFlag()) {
3362 Status = EFI_ABORTED;
3363 break;
3364 }
3365 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3366 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3367 if (EFI_ERROR(Status)) {
3368 break;
3369 }
3370 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3371 switch (Key.UnicodeChar) {
3372 case L'Y':
3373 case L'y':
3374 *Resp = ShellPromptResponseYes;
3375 break;
3376 case L'N':
3377 case L'n':
3378 *Resp = ShellPromptResponseNo;
3379 break;
3380 case L'C':
3381 case L'c':
3382 *Resp = ShellPromptResponseCancel;
3383 break;
3384 }
3385 }
3386 break; case ShellPromptResponseTypeYesNoAllCancel:
3387 if (Prompt != NULL) {
3388 ShellPrintEx(-1, -1, L"%s", Prompt);
3389 }
3390 //
3391 // wait for valid response
3392 //
3393 *Resp = ShellPromptResponseMax;
3394 while (*Resp == ShellPromptResponseMax) {
3395 if (ShellGetExecutionBreakFlag()) {
3396 Status = EFI_ABORTED;
3397 break;
3398 }
3399 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3400 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3401 if (EFI_ERROR(Status)) {
3402 break;
3403 }
3404 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3405 switch (Key.UnicodeChar) {
3406 case L'Y':
3407 case L'y':
3408 *Resp = ShellPromptResponseYes;
3409 break;
3410 case L'N':
3411 case L'n':
3412 *Resp = ShellPromptResponseNo;
3413 break;
3414 case L'A':
3415 case L'a':
3416 *Resp = ShellPromptResponseAll;
3417 break;
3418 case L'C':
3419 case L'c':
3420 *Resp = ShellPromptResponseCancel;
3421 break;
3422 }
3423 }
3424 break;
3425 case ShellPromptResponseTypeEnterContinue:
3426 case ShellPromptResponseTypeAnyKeyContinue:
3427 if (Prompt != NULL) {
3428 ShellPrintEx(-1, -1, L"%s", Prompt);
3429 }
3430 //
3431 // wait for valid response
3432 //
3433 *Resp = ShellPromptResponseMax;
3434 while (*Resp == ShellPromptResponseMax) {
3435 if (ShellGetExecutionBreakFlag()) {
3436 Status = EFI_ABORTED;
3437 break;
3438 }
3439 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3440 if (Type == ShellPromptResponseTypeEnterContinue) {
3441 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3442 if (EFI_ERROR(Status)) {
3443 break;
3444 }
3445 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3446 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
3447 *Resp = ShellPromptResponseContinue;
3448 break;
3449 }
3450 }
3451 if (Type == ShellPromptResponseTypeAnyKeyContinue) {
3452 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3453 ASSERT_EFI_ERROR(Status);
3454 *Resp = ShellPromptResponseContinue;
3455 break;
3456 }
3457 }
3458 break;
3459 case ShellPromptResponseTypeYesNo:
3460 if (Prompt != NULL) {
3461 ShellPrintEx(-1, -1, L"%s", Prompt);
3462 }
3463 //
3464 // wait for valid response
3465 //
3466 *Resp = ShellPromptResponseMax;
3467 while (*Resp == ShellPromptResponseMax) {
3468 if (ShellGetExecutionBreakFlag()) {
3469 Status = EFI_ABORTED;
3470 break;
3471 }
3472 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3473 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3474 if (EFI_ERROR(Status)) {
3475 break;
3476 }
3477 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3478 switch (Key.UnicodeChar) {
3479 case L'Y':
3480 case L'y':
3481 *Resp = ShellPromptResponseYes;
3482 break;
3483 case L'N':
3484 case L'n':
3485 *Resp = ShellPromptResponseNo;
3486 break;
3487 }
3488 }
3489 break;
3490 case ShellPromptResponseTypeFreeform:
3491 if (Prompt != NULL) {
3492 ShellPrintEx(-1, -1, L"%s", Prompt);
3493 }
3494 while(1) {
3495 if (ShellGetExecutionBreakFlag()) {
3496 Status = EFI_ABORTED;
3497 break;
3498 }
3499 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);
3500 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
3501 if (EFI_ERROR(Status)) {
3502 break;
3503 }
3504 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);
3505 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
3506 break;
3507 }
3508 ASSERT((Buffer == NULL && Size == 0) || (Buffer != NULL));
3509 StrnCatGrow(&Buffer, &Size, &Key.UnicodeChar, 1);
3510 }
3511 break;
3512 //
3513 // This is the location to add new prompt types.
3514 // If your new type loops remember to add ExecutionBreak support.
3515 //
3516 default:
3517 ASSERT(FALSE);
3518 }
3519
3520 if (Response != NULL) {
3521 if (Resp != NULL) {
3522 *Response = Resp;
3523 } else if (Buffer != NULL) {
3524 *Response = Buffer;
3525 }
3526 } else {
3527 if (Resp != NULL) {
3528 FreePool(Resp);
3529 }
3530 if (Buffer != NULL) {
3531 FreePool(Buffer);
3532 }
3533 }
3534
3535 ShellPrintEx(-1, -1, L"\r\n");
3536 return (Status);
3537 }
3538
3539 /**
3540 Prompt the user and return the resultant answer to the requestor.
3541
3542 This function is the same as ShellPromptForResponse, except that the prompt is
3543 automatically pulled from HII.
3544
3545 @param Type What type of question is asked. This is used to filter the input
3546 to prevent invalid answers to question.
3547 @param[in] HiiFormatStringId The format string Id for getting from Hii.
3548 @param[in] HiiFormatHandle The format string Handle for getting from Hii.
3549 @param Response Pointer to Response which will be populated upon return.
3550
3551 @retval EFI_SUCCESS the operation was sucessful.
3552 @return other the operation failed.
3553
3554 @sa ShellPromptForResponse
3555 **/
3556 EFI_STATUS
3557 EFIAPI
3558 ShellPromptForResponseHii (
3559 IN SHELL_PROMPT_REQUEST_TYPE Type,
3560 IN CONST EFI_STRING_ID HiiFormatStringId,
3561 IN CONST EFI_HANDLE HiiFormatHandle,
3562 IN OUT VOID **Response
3563 )
3564 {
3565 CHAR16 *Prompt;
3566 EFI_STATUS Status;
3567
3568 Prompt = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL);
3569 Status = ShellPromptForResponse(Type, Prompt, Response);
3570 FreePool(Prompt);
3571 return (Status);
3572 }
3573
3574 /**
3575 Function to determin if an entire string is a valid number.
3576
3577 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
3578
3579 @param[in] String The string to evaluate.
3580 @param[in] ForceHex TRUE - always assume hex.
3581 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
3582 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.
3583
3584 @retval TRUE It is all numeric (dec/hex) characters.
3585 @retval FALSE There is a non-numeric character.
3586 **/
3587 BOOLEAN
3588 EFIAPI
3589 InternalShellIsHexOrDecimalNumber (
3590 IN CONST CHAR16 *String,
3591 IN CONST BOOLEAN ForceHex,
3592 IN CONST BOOLEAN StopAtSpace,
3593 IN CONST BOOLEAN TimeNumbers
3594 )
3595 {
3596 BOOLEAN Hex;
3597
3598 //
3599 // chop off a single negative sign
3600 //
3601 if (String != NULL && *String == L'-') {
3602 String++;
3603 }
3604
3605 if (String == NULL) {
3606 return (FALSE);
3607 }
3608
3609 //
3610 // chop leading zeroes
3611 //
3612 while(String != NULL && *String == L'0'){
3613 String++;
3614 }
3615 //
3616 // allow '0x' or '0X', but not 'x' or 'X'
3617 //
3618 if (String != NULL && (*String == L'x' || *String == L'X')) {
3619 if (*(String-1) != L'0') {
3620 //
3621 // we got an x without a preceeding 0
3622 //
3623 return (FALSE);
3624 }
3625 String++;
3626 Hex = TRUE;
3627 } else if (ForceHex) {
3628 Hex = TRUE;
3629 } else {
3630 Hex = FALSE;
3631 }
3632
3633 //
3634 // loop through the remaining characters and use the lib function
3635 //
3636 for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){
3637 if (TimeNumbers && (String[0] == L':')) {
3638 continue;
3639 }
3640 if (Hex) {
3641 if (!ShellIsHexaDecimalDigitCharacter(*String)) {
3642 return (FALSE);
3643 }
3644 } else {
3645 if (!ShellIsDecimalDigitCharacter(*String)) {
3646 return (FALSE);
3647 }
3648 }
3649 }
3650
3651 return (TRUE);
3652 }
3653
3654 /**
3655 Function to determine if a given filename exists.
3656
3657 @param[in] Name Path to test.
3658
3659 @retval EFI_SUCCESS The Path represents a file.
3660 @retval EFI_NOT_FOUND The Path does not represent a file.
3661 @retval other The path failed to open.
3662 **/
3663 EFI_STATUS
3664 EFIAPI
3665 ShellFileExists(
3666 IN CONST CHAR16 *Name
3667 )
3668 {
3669 EFI_STATUS Status;
3670 EFI_SHELL_FILE_INFO *List;
3671
3672 ASSERT(Name != NULL);
3673
3674 List = NULL;
3675 Status = ShellOpenFileMetaArg((CHAR16*)Name, EFI_FILE_MODE_READ, &List);
3676 if (EFI_ERROR(Status)) {
3677 return (Status);
3678 }
3679
3680 ShellCloseFileMetaArg(&List);
3681
3682 return (EFI_SUCCESS);
3683 }
3684
3685 /**
3686 Convert a Unicode character to upper case only if
3687 it maps to a valid small-case ASCII character.
3688
3689 This internal function only deal with Unicode character
3690 which maps to a valid small-case ASCII character, i.e.
3691 L'a' to L'z'. For other Unicode character, the input character
3692 is returned directly.
3693
3694 @param Char The character to convert.
3695
3696 @retval LowerCharacter If the Char is with range L'a' to L'z'.
3697 @retval Unchanged Otherwise.
3698
3699 **/
3700 CHAR16
3701 EFIAPI
3702 InternalShellCharToUpper (
3703 IN CHAR16 Char
3704 )
3705 {
3706 if (Char >= L'a' && Char <= L'z') {
3707 return (CHAR16) (Char - (L'a' - L'A'));
3708 }
3709
3710 return Char;
3711 }
3712
3713 /**
3714 Convert a Unicode character to numerical value.
3715
3716 This internal function only deal with Unicode character
3717 which maps to a valid hexadecimal ASII character, i.e.
3718 L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other
3719 Unicode character, the value returned does not make sense.
3720
3721 @param Char The character to convert.
3722
3723 @return The numerical value converted.
3724
3725 **/
3726 UINTN
3727 EFIAPI
3728 InternalShellHexCharToUintn (
3729 IN CHAR16 Char
3730 )
3731 {
3732 if (ShellIsDecimalDigitCharacter (Char)) {
3733 return Char - L'0';
3734 }
3735
3736 return (UINTN) (10 + InternalShellCharToUpper (Char) - L'A');
3737 }
3738
3739 /**
3740 Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.
3741
3742 This function returns a value of type UINT64 by interpreting the contents
3743 of the Unicode string specified by String as a hexadecimal number.
3744 The format of the input Unicode string String is:
3745
3746 [spaces][zeros][x][hexadecimal digits].
3747
3748 The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
3749 The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
3750 If "x" appears in the input string, it must be prefixed with at least one 0.
3751 The function will ignore the pad space, which includes spaces or tab characters,
3752 before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or
3753 [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the
3754 first valid hexadecimal digit. Then, the function stops at the first character that is
3755 a not a valid hexadecimal character or NULL, whichever one comes first.
3756
3757 If String has only pad spaces, then zero is returned.
3758 If String has no leading pad spaces, leading zeros or valid hexadecimal digits,
3759 then zero is returned.
3760
3761 @param[in] String A pointer to a Null-terminated Unicode string.
3762 @param[out] Value Upon a successful return the value of the conversion.
3763 @param[in] StopAtSpace FALSE to skip spaces.
3764
3765 @retval EFI_SUCCESS The conversion was successful.
3766 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3767 @retval EFI_DEVICE_ERROR An overflow occured.
3768 **/
3769 EFI_STATUS
3770 EFIAPI
3771 InternalShellStrHexToUint64 (
3772 IN CONST CHAR16 *String,
3773 OUT UINT64 *Value,
3774 IN CONST BOOLEAN StopAtSpace
3775 )
3776 {
3777 UINT64 Result;
3778
3779 if (String == NULL || StrSize(String) == 0 || Value == NULL) {
3780 return (EFI_INVALID_PARAMETER);
3781 }
3782
3783 //
3784 // Ignore the pad spaces (space or tab)
3785 //
3786 while ((*String == L' ') || (*String == L'\t')) {
3787 String++;
3788 }
3789
3790 //
3791 // Ignore leading Zeros after the spaces
3792 //
3793 while (*String == L'0') {
3794 String++;
3795 }
3796
3797 if (InternalShellCharToUpper (*String) == L'X') {
3798 if (*(String - 1) != L'0') {
3799 return 0;
3800 }
3801 //
3802 // Skip the 'X'
3803 //
3804 String++;
3805 }
3806
3807 Result = 0;
3808
3809 //
3810 // there is a space where there should't be
3811 //
3812 if (*String == L' ') {
3813 return (EFI_INVALID_PARAMETER);
3814 }
3815
3816 while (ShellIsHexaDecimalDigitCharacter (*String)) {
3817 //
3818 // If the Hex Number represented by String overflows according
3819 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3820 //
3821 if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {
3822 // if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {
3823 return (EFI_DEVICE_ERROR);
3824 }
3825
3826 Result = (LShiftU64(Result, 4));
3827 Result += InternalShellHexCharToUintn (*String);
3828 String++;
3829
3830 //
3831 // stop at spaces if requested
3832 //
3833 if (StopAtSpace && *String == L' ') {
3834 break;
3835 }
3836 }
3837
3838 *Value = Result;
3839 return (EFI_SUCCESS);
3840 }
3841
3842 /**
3843 Convert a Null-terminated Unicode decimal string to a value of
3844 type UINT64.
3845
3846 This function returns a value of type UINT64 by interpreting the contents
3847 of the Unicode string specified by String as a decimal number. The format
3848 of the input Unicode string String is:
3849
3850 [spaces] [decimal digits].
3851
3852 The valid decimal digit character is in the range [0-9]. The
3853 function will ignore the pad space, which includes spaces or
3854 tab characters, before [decimal digits]. The running zero in the
3855 beginning of [decimal digits] will be ignored. Then, the function
3856 stops at the first character that is a not a valid decimal character
3857 or a Null-terminator, whichever one comes first.
3858
3859 If String has only pad spaces, then 0 is returned.
3860 If String has no pad spaces or valid decimal digits,
3861 then 0 is returned.
3862
3863 @param[in] String A pointer to a Null-terminated Unicode string.
3864 @param[out] Value Upon a successful return the value of the conversion.
3865 @param[in] StopAtSpace FALSE to skip spaces.
3866
3867 @retval EFI_SUCCESS The conversion was successful.
3868 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.
3869 @retval EFI_DEVICE_ERROR An overflow occured.
3870 **/
3871 EFI_STATUS
3872 EFIAPI
3873 InternalShellStrDecimalToUint64 (
3874 IN CONST CHAR16 *String,
3875 OUT UINT64 *Value,
3876 IN CONST BOOLEAN StopAtSpace
3877 )
3878 {
3879 UINT64 Result;
3880
3881 if (String == NULL || StrSize (String) == 0 || Value == NULL) {
3882 return (EFI_INVALID_PARAMETER);
3883 }
3884
3885 //
3886 // Ignore the pad spaces (space or tab)
3887 //
3888 while ((*String == L' ') || (*String == L'\t')) {
3889 String++;
3890 }
3891
3892 //
3893 // Ignore leading Zeros after the spaces
3894 //
3895 while (*String == L'0') {
3896 String++;
3897 }
3898
3899 Result = 0;
3900
3901 //
3902 // Stop upon space if requested
3903 // (if the whole value was 0)
3904 //
3905 if (StopAtSpace && *String == L' ') {
3906 *Value = Result;
3907 return (EFI_SUCCESS);
3908 }
3909
3910 while (ShellIsDecimalDigitCharacter (*String)) {
3911 //
3912 // If the number represented by String overflows according
3913 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.
3914 //
3915
3916 if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) {
3917 return (EFI_DEVICE_ERROR);
3918 }
3919
3920 Result = MultU64x32(Result, 10) + (*String - L'0');
3921 String++;
3922
3923 //
3924 // Stop at spaces if requested
3925 //
3926 if (StopAtSpace && *String == L' ') {
3927 break;
3928 }
3929 }
3930
3931 *Value = Result;
3932
3933 return (EFI_SUCCESS);
3934 }
3935
3936 /**
3937 Function to verify and convert a string to its numerical value.
3938
3939 If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.
3940
3941 @param[in] String The string to evaluate.
3942 @param[out] Value Upon a successful return the value of the conversion.
3943 @param[in] ForceHex TRUE - always assume hex.
3944 @param[in] StopAtSpace FALSE to skip spaces.
3945
3946 @retval EFI_SUCCESS The conversion was successful.
3947 @retval EFI_INVALID_PARAMETER String contained an invalid character.
3948 @retval EFI_NOT_FOUND String was a number, but Value was NULL.
3949 **/
3950 EFI_STATUS
3951 EFIAPI
3952 ShellConvertStringToUint64(
3953 IN CONST CHAR16 *String,
3954 OUT UINT64 *Value,
3955 IN CONST BOOLEAN ForceHex,
3956 IN CONST BOOLEAN StopAtSpace
3957 )
3958 {
3959 UINT64 RetVal;
3960 CONST CHAR16 *Walker;
3961 EFI_STATUS Status;
3962 BOOLEAN Hex;
3963
3964 Hex = ForceHex;
3965
3966 if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
3967 if (!Hex) {
3968 Hex = TRUE;
3969 if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {
3970 return (EFI_INVALID_PARAMETER);
3971 }
3972 } else {
3973 return (EFI_INVALID_PARAMETER);
3974 }
3975 }
3976
3977 //
3978 // Chop off leading spaces
3979 //
3980 for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);
3981
3982 //
3983 // make sure we have something left that is numeric.
3984 //
3985 if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) {
3986 return (EFI_INVALID_PARAMETER);
3987 }
3988
3989 //
3990 // do the conversion.
3991 //
3992 if (Hex || StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){
3993 Status = InternalShellStrHexToUint64(Walker, &RetVal, StopAtSpace);
3994 } else {
3995 Status = InternalShellStrDecimalToUint64(Walker, &RetVal, StopAtSpace);
3996 }
3997
3998 if (Value == NULL && !EFI_ERROR(Status)) {
3999 return (EFI_NOT_FOUND);
4000 }
4001
4002 if (Value != NULL) {
4003 *Value = RetVal;
4004 }
4005
4006 return (Status);
4007 }
4008
4009 /**
4010 Function to determin if an entire string is a valid number.
4011
4012 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.
4013
4014 @param[in] String The string to evaluate.
4015 @param[in] ForceHex TRUE - always assume hex.
4016 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.
4017
4018 @retval TRUE It is all numeric (dec/hex) characters.
4019 @retval FALSE There is a non-numeric character.
4020 **/
4021 BOOLEAN
4022 EFIAPI
4023 ShellIsHexOrDecimalNumber (
4024 IN CONST CHAR16 *String,
4025 IN CONST BOOLEAN ForceHex,
4026 IN CONST BOOLEAN StopAtSpace
4027 )
4028 {
4029 if (ShellConvertStringToUint64(String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) {
4030 return (TRUE);
4031 }
4032 return (FALSE);
4033 }
4034
4035 /**
4036 Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned
4037 buffer. The returned buffer must be callee freed.
4038
4039 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4040 maintained and not changed for all operations with the same file.
4041
4042 @param[in] Handle SHELL_FILE_HANDLE to read from.
4043 @param[in, out] Ascii Boolean value for indicating whether the file is
4044 Ascii (TRUE) or UCS2 (FALSE).
4045
4046 @return The line of text from the file.
4047 @retval NULL There was not enough memory available.
4048
4049 @sa ShellFileHandleReadLine
4050 **/
4051 CHAR16*
4052 EFIAPI
4053 ShellFileHandleReturnLine(
4054 IN SHELL_FILE_HANDLE Handle,
4055 IN OUT BOOLEAN *Ascii
4056 )
4057 {
4058 CHAR16 *RetVal;
4059 UINTN Size;
4060 EFI_STATUS Status;
4061
4062 Size = 0;
4063 RetVal = NULL;
4064
4065 Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
4066 if (Status == EFI_BUFFER_TOO_SMALL) {
4067 RetVal = AllocateZeroPool(Size);
4068 if (RetVal == NULL) {
4069 return (NULL);
4070 }
4071 Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);
4072
4073 }
4074 if (EFI_ERROR(Status) && (RetVal != NULL)) {
4075 FreePool(RetVal);
4076 RetVal = NULL;
4077 }
4078 return (RetVal);
4079 }
4080
4081 /**
4082 Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.
4083
4084 If the position upon start is 0, then the Ascii Boolean will be set. This should be
4085 maintained and not changed for all operations with the same file.
4086
4087 NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ
4088 IS IN ASCII FORMAT.
4089
4090 @param[in] Handle SHELL_FILE_HANDLE to read from.
4091 @param[in, out] Buffer The pointer to buffer to read into. If this function
4092 returns EFI_SUCCESS, then on output Buffer will
4093 contain a UCS2 string, even if the file being
4094 read is ASCII.
4095 @param[in, out] Size On input, pointer to number of bytes in Buffer.
4096 On output, unchanged unless Buffer is too small
4097 to contain the next line of the file. In that
4098 case Size is set to the number of bytes needed
4099 to hold the next line of the file (as a UCS2
4100 string, even if it is an ASCII file).
4101 @param[in] Truncate If the buffer is large enough, this has no effect.
4102 If the buffer is is too small and Truncate is TRUE,
4103 the line will be truncated.
4104 If the buffer is is too small and Truncate is FALSE,
4105 then no read will occur.
4106
4107 @param[in, out] Ascii Boolean value for indicating whether the file is
4108 Ascii (TRUE) or UCS2 (FALSE).
4109
4110 @retval EFI_SUCCESS The operation was successful. The line is stored in
4111 Buffer.
4112 @retval EFI_END_OF_FILE There are no more lines in the file.
4113 @retval EFI_INVALID_PARAMETER Handle was NULL.
4114 @retval EFI_INVALID_PARAMETER Size was NULL.
4115 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.
4116 Size was updated to the minimum space required.
4117 **/
4118 EFI_STATUS
4119 EFIAPI
4120 ShellFileHandleReadLine(
4121 IN SHELL_FILE_HANDLE Handle,
4122 IN OUT CHAR16 *Buffer,
4123 IN OUT UINTN *Size,
4124 IN BOOLEAN Truncate,
4125 IN OUT BOOLEAN *Ascii
4126 )
4127 {
4128 EFI_STATUS Status;
4129 CHAR16 CharBuffer;
4130 UINTN CharSize;
4131 UINTN CountSoFar;
4132 UINT64 OriginalFilePosition;
4133
4134
4135 if (Handle == NULL
4136 ||Size == NULL
4137 ){
4138 return (EFI_INVALID_PARAMETER);
4139 }
4140 if (Buffer == NULL) {
4141 ASSERT(*Size == 0);
4142 } else {
4143 *Buffer = CHAR_NULL;
4144 }
4145 gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);
4146 if (OriginalFilePosition == 0) {
4147 CharSize = sizeof(CHAR16);
4148 Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
4149 ASSERT_EFI_ERROR(Status);
4150 if (CharBuffer == gUnicodeFileTag) {
4151 *Ascii = FALSE;
4152 } else {
4153 *Ascii = TRUE;
4154 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
4155 }
4156 }
4157
4158 if (*Ascii) {
4159 CharSize = sizeof(CHAR8);
4160 } else {
4161 CharSize = sizeof(CHAR16);
4162 }
4163 for (CountSoFar = 0;;CountSoFar++){
4164 CharBuffer = 0;
4165 Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);
4166 if ( EFI_ERROR(Status)
4167 || CharSize == 0
4168 || (CharBuffer == L'\n' && !(*Ascii))
4169 || (CharBuffer == '\n' && *Ascii)
4170 ){
4171 if (CharSize == 0) {
4172 Status = EFI_END_OF_FILE;
4173 }
4174 break;
4175 }
4176 //
4177 // if we have space save it...
4178 //
4179 if ((CountSoFar + 1) * CharSize < *Size){
4180 ASSERT(Buffer != NULL);
4181 if (*Ascii) {
4182 ((CHAR8*)Buffer)[CountSoFar] = (CHAR8) CharBuffer;
4183 ((CHAR8*)Buffer)[CountSoFar+1] = '\0';
4184 }
4185 else {
4186 ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;
4187 ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;
4188 }
4189 }
4190 }
4191
4192 //
4193 // if we ran out of space tell when...
4194 //
4195 if (Status != EFI_END_OF_FILE){
4196 if ((CountSoFar + 1) * CharSize > *Size){
4197 *Size = (CountSoFar + 1) * CharSize;
4198 if (!Truncate) {
4199 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
4200 } else {
4201 DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
4202 }
4203 return (EFI_BUFFER_TOO_SMALL);
4204 }
4205
4206 if (*Ascii) {
4207 if (CountSoFar && ((CHAR8*)Buffer)[CountSoFar - 1] == '\r') {
4208 ((CHAR8*)Buffer)[CountSoFar - 1] = '\0';
4209 }
4210 }
4211 else {
4212 if (CountSoFar && Buffer[CountSoFar - 1] == L'\r') {
4213 Buffer[CountSoFar - 1] = CHAR_NULL;
4214 }
4215 }
4216 }
4217
4218 return (Status);
4219 }
4220
4221 /**
4222 Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.
4223
4224 @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.
4225 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).
4226 @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints
4227 the help content only.
4228 @retval EFI_DEVICE_ERROR The help data format was incorrect.
4229 @retval EFI_NOT_FOUND The help data could not be found.
4230 @retval EFI_SUCCESS The operation was successful.
4231 **/
4232 EFI_STATUS
4233 EFIAPI
4234 ShellPrintHelp (
4235 IN CONST CHAR16 *CommandToGetHelpOn,
4236 IN CONST CHAR16 *SectionToGetHelpOn,
4237 IN BOOLEAN PrintCommandText
4238 )
4239 {
4240 EFI_STATUS Status;
4241 CHAR16 *OutText;
4242
4243 OutText = NULL;
4244
4245 //
4246 // Get the string to print based
4247 //
4248 Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);
4249
4250 //
4251 // make sure we got a valid string
4252 //
4253 if (EFI_ERROR(Status)){
4254 return Status;
4255 }
4256 if (OutText == NULL || StrLen(OutText) == 0) {
4257 return EFI_NOT_FOUND;
4258 }
4259
4260 //
4261 // Chop off trailing stuff we dont need
4262 //
4263 while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') {
4264 OutText[StrLen(OutText)-1] = CHAR_NULL;
4265 }
4266
4267 //
4268 // Print this out to the console
4269 //
4270 if (PrintCommandText) {
4271 ShellPrintEx(-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);
4272 } else {
4273 ShellPrintEx(-1, -1, L"%N%s\r\n", OutText);
4274 }
4275
4276 SHELL_FREE_NON_NULL(OutText);
4277
4278 return EFI_SUCCESS;
4279 }
4280
4281 /**
4282 Function to delete a file by name
4283
4284 @param[in] FileName Pointer to file name to delete.
4285
4286 @retval EFI_SUCCESS the file was deleted sucessfully
4287 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not
4288 deleted
4289 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
4290 @retval EFI_NOT_FOUND The specified file could not be found on the
4291 device or the file system could not be found
4292 on the device.
4293 @retval EFI_NO_MEDIA The device has no medium.
4294 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
4295 medium is no longer supported.
4296 @retval EFI_DEVICE_ERROR The device reported an error.
4297 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
4298 @retval EFI_WRITE_PROTECTED The file or medium is write protected.
4299 @retval EFI_ACCESS_DENIED The file was opened read only.
4300 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
4301 file.
4302 @retval other The file failed to open
4303 **/
4304 EFI_STATUS
4305 EFIAPI
4306 ShellDeleteFileByName(
4307 IN CONST CHAR16 *FileName
4308 )
4309 {
4310 EFI_STATUS Status;
4311 SHELL_FILE_HANDLE FileHandle;
4312
4313 Status = ShellFileExists(FileName);
4314
4315 if (Status == EFI_SUCCESS){
4316 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);
4317 if (Status == EFI_SUCCESS){
4318 Status = ShellDeleteFile(&FileHandle);
4319 }
4320 }
4321
4322 return(Status);
4323
4324 }
4325
4326 /**
4327 Cleans off all the quotes in the string.
4328
4329 @param[in] OriginalString pointer to the string to be cleaned.
4330 @param[out] CleanString The new string with all quotes removed.
4331 Memory allocated in the function and free
4332 by caller.
4333
4334 @retval EFI_SUCCESS The operation was successful.
4335 **/
4336 EFI_STATUS
4337 EFIAPI
4338 InternalShellStripQuotes (
4339 IN CONST CHAR16 *OriginalString,
4340 OUT CHAR16 **CleanString
4341 )
4342 {
4343 CHAR16 *Walker;
4344
4345 if (OriginalString == NULL || CleanString == NULL) {
4346 return EFI_INVALID_PARAMETER;
4347 }
4348
4349 *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);
4350 if (*CleanString == NULL) {
4351 return EFI_OUT_OF_RESOURCES;
4352 }
4353
4354 for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
4355 if (*Walker == L'\"') {
4356 CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
4357 }
4358 }
4359
4360 return EFI_SUCCESS;
4361 }
4362