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