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