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