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