]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLib/UefiShellLib.c
ShellPkg: Replace BSD License with BSD+Patent License
[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 // Due to oddity in the EFI shell we want to dereference the ParentHandle here\r
1295 //\r
3877d0f5 1296 CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,\r
92a5447e 1297 CommandLine,\r
1298 Output));\r
3877d0f5
BJ
1299 //\r
1300 // No Status output parameter so just use the returned status\r
1301 //\r
1302 if (Status != NULL) {\r
1303 *Status = CmdStatus;\r
1304 }\r
1305 //\r
1306 // If there was an error, we can't tell if it was from the command or from\r
1307 // the Execute() function, so we'll just assume the shell ran successfully\r
1308 // and the error came from the command.\r
1309 //\r
1310 return EFI_SUCCESS;\r
92a5447e 1311 }\r
1312\r
1313 return (EFI_UNSUPPORTED);\r
94b17fa1 1314}\r
3877d0f5 1315\r
94b17fa1 1316/**\r
1317 Retreives the current directory path\r
1318\r
1e6e84c7 1319 If the DeviceName is NULL, it returns the current device's current directory\r
1320 name. If the DeviceName is not NULL, it returns the current directory name\r
94b17fa1 1321 on specified drive.\r
1322\r
fbd2dfad
QS
1323 Note that the current directory string should exclude the tailing backslash character.\r
1324\r
94b17fa1 1325 @param DeviceName the name of the drive to get directory on\r
1326\r
1327 @retval NULL the directory does not exist\r
1328 @return != NULL the directory\r
1329**/\r
1330CONST CHAR16*\r
1331EFIAPI\r
1332ShellGetCurrentDir (\r
a405b86d 1333 IN CHAR16 * CONST DeviceName OPTIONAL\r
94b17fa1 1334 )\r
1335{\r
1e6e84c7 1336 //\r
94b17fa1 1337 // Check for UEFI Shell 2.0 protocols\r
1338 //\r
366f81a0 1339 if (gEfiShellProtocol != NULL) {\r
1340 return (gEfiShellProtocol->GetCurDir(DeviceName));\r
1e6e84c7 1341 }\r
92a5447e 1342\r
94b17fa1 1343 //\r
8bd282be 1344 // Check for EFI shell\r
94b17fa1 1345 //\r
8bd282be 1346 if (mEfiShellEnvironment2 != NULL) {\r
1347 return (mEfiShellEnvironment2->CurDir(DeviceName));\r
1348 }\r
1349\r
1350 return (NULL);\r
94b17fa1 1351}\r
1352/**\r
1353 sets (enabled or disabled) the page break mode\r
1354\r
1e6e84c7 1355 when page break mode is enabled the screen will stop scrolling\r
94b17fa1 1356 and wait for operator input before scrolling a subsequent screen.\r
1357\r
1358 @param CurrentState TRUE to enable and FALSE to disable\r
1359**/\r
1e6e84c7 1360VOID\r
94b17fa1 1361EFIAPI\r
1362ShellSetPageBreakMode (\r
1363 IN BOOLEAN CurrentState\r
1364 )\r
1365{\r
1366 //\r
1367 // check for enabling\r
1368 //\r
1369 if (CurrentState != 0x00) {\r
1e6e84c7 1370 //\r
94b17fa1 1371 // check for UEFI Shell 2.0\r
1372 //\r
366f81a0 1373 if (gEfiShellProtocol != NULL) {\r
94b17fa1 1374 //\r
1375 // Enable with UEFI 2.0 Shell\r
1376 //\r
366f81a0 1377 gEfiShellProtocol->EnablePageBreak();\r
94b17fa1 1378 return;\r
1379 } else {\r
1e6e84c7 1380 //\r
92a5447e 1381 // Check for EFI shell\r
94b17fa1 1382 //\r
92a5447e 1383 if (mEfiShellEnvironment2 != NULL) {\r
1384 //\r
1385 // Enable with EFI Shell\r
1386 //\r
1387 mEfiShellEnvironment2->EnablePageBreak (DEFAULT_INIT_ROW, DEFAULT_AUTO_LF);\r
1388 return;\r
1389 }\r
94b17fa1 1390 }\r
1391 } else {\r
1e6e84c7 1392 //\r
94b17fa1 1393 // check for UEFI Shell 2.0\r
1394 //\r
366f81a0 1395 if (gEfiShellProtocol != NULL) {\r
94b17fa1 1396 //\r
1397 // Disable with UEFI 2.0 Shell\r
1398 //\r
366f81a0 1399 gEfiShellProtocol->DisablePageBreak();\r
94b17fa1 1400 return;\r
1401 } else {\r
1e6e84c7 1402 //\r
92a5447e 1403 // Check for EFI shell\r
94b17fa1 1404 //\r
92a5447e 1405 if (mEfiShellEnvironment2 != NULL) {\r
1406 //\r
1407 // Disable with EFI Shell\r
1408 //\r
1409 mEfiShellEnvironment2->DisablePageBreak ();\r
1410 return;\r
1411 }\r
94b17fa1 1412 }\r
1413 }\r
1414}\r
1415\r
1416///\r
1417/// version of EFI_SHELL_FILE_INFO struct, except has no CONST pointers.\r
1418/// This allows for the struct to be populated.\r
1419///\r
1420typedef struct {\r
d2b4564b 1421 LIST_ENTRY Link;\r
94b17fa1 1422 EFI_STATUS Status;\r
1423 CHAR16 *FullName;\r
1424 CHAR16 *FileName;\r
a405b86d 1425 SHELL_FILE_HANDLE Handle;\r
94b17fa1 1426 EFI_FILE_INFO *Info;\r
1427} EFI_SHELL_FILE_INFO_NO_CONST;\r
1428\r
1429/**\r
1430 Converts a EFI shell list of structures to the coresponding UEFI Shell 2.0 type of list.\r
1431\r
1432 if OldStyleFileList is NULL then ASSERT()\r
1433\r
1e6e84c7 1434 this function will convert a SHELL_FILE_ARG based list into a callee allocated\r
94b17fa1 1435 EFI_SHELL_FILE_INFO based list. it is up to the caller to free the memory via\r
1436 the ShellCloseFileMetaArg function.\r
1437\r
4ff7e37b
ED
1438 @param[in] FileList the EFI shell list type\r
1439 @param[in, out] ListHead the list to add to\r
94b17fa1 1440\r
1441 @retval the resultant head of the double linked new format list;\r
1442**/\r
1443LIST_ENTRY*\r
94b17fa1 1444InternalShellConvertFileListType (\r
9b3bf083 1445 IN LIST_ENTRY *FileList,\r
1446 IN OUT LIST_ENTRY *ListHead\r
125c2cf4 1447 )\r
1448{\r
94b17fa1 1449 SHELL_FILE_ARG *OldInfo;\r
9b3bf083 1450 LIST_ENTRY *Link;\r
94b17fa1 1451 EFI_SHELL_FILE_INFO_NO_CONST *NewInfo;\r
1452\r
1453 //\r
9b3bf083 1454 // ASSERTs\r
94b17fa1 1455 //\r
9b3bf083 1456 ASSERT(FileList != NULL);\r
1457 ASSERT(ListHead != NULL);\r
94b17fa1 1458\r
1459 //\r
1460 // enumerate through each member of the old list and copy\r
1461 //\r
d2b4564b 1462 for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {\r
94b17fa1 1463 OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);\r
a405b86d 1464 ASSERT(OldInfo != NULL);\r
1465\r
1466 //\r
1467 // Skip ones that failed to open...\r
1468 //\r
1469 if (OldInfo->Status != EFI_SUCCESS) {\r
1470 continue;\r
1471 }\r
94b17fa1 1472\r
1473 //\r
1474 // make sure the old list was valid\r
1475 //\r
94b17fa1 1476 ASSERT(OldInfo->Info != NULL);\r
1477 ASSERT(OldInfo->FullName != NULL);\r
1478 ASSERT(OldInfo->FileName != NULL);\r
1479\r
1480 //\r
1481 // allocate a new EFI_SHELL_FILE_INFO object\r
1482 //\r
1483 NewInfo = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
c9d92df0 1484 if (NewInfo == NULL) {\r
7a95efda 1485 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));\r
beab0fc5 1486 ListHead = NULL;\r
c9d92df0 1487 break;\r
1488 }\r
1e6e84c7 1489\r
1490 //\r
94b17fa1 1491 // copy the simple items\r
1492 //\r
1493 NewInfo->Handle = OldInfo->Handle;\r
1494 NewInfo->Status = OldInfo->Status;\r
1495\r
d2b4564b 1496 // old shell checks for 0 not NULL\r
1497 OldInfo->Handle = 0;\r
1498\r
94b17fa1 1499 //\r
1500 // allocate new space to copy strings and structure\r
1501 //\r
98c16be5
JC
1502 NewInfo->FullName = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);\r
1503 NewInfo->FileName = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);\r
1504 NewInfo->Info = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);\r
1e6e84c7 1505\r
94b17fa1 1506 //\r
1507 // make sure all the memory allocations were sucessful\r
1508 //\r
beab0fc5 1509 if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {\r
98c16be5
JC
1510 //\r
1511 // Free the partially allocated new node\r
1512 //\r
1513 SHELL_FREE_NON_NULL(NewInfo->FullName);\r
1514 SHELL_FREE_NON_NULL(NewInfo->FileName);\r
1515 SHELL_FREE_NON_NULL(NewInfo->Info);\r
1516 SHELL_FREE_NON_NULL(NewInfo);\r
1517\r
1518 //\r
1519 // Free the previously converted stuff\r
1520 //\r
7a95efda 1521 ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));\r
beab0fc5 1522 ListHead = NULL;\r
1523 break;\r
1524 }\r
94b17fa1 1525\r
94b17fa1 1526 //\r
1527 // add that to the list\r
1528 //\r
9b3bf083 1529 InsertTailList(ListHead, &NewInfo->Link);\r
94b17fa1 1530 }\r
1531 return (ListHead);\r
1532}\r
1533/**\r
1534 Opens a group of files based on a path.\r
1535\r
1e6e84c7 1536 This function uses the Arg to open all the matching files. Each matched\r
70879314
BJ
1537 file has a SHELL_FILE_INFO structure to record the file information. These\r
1538 structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO\r
94b17fa1 1539 structures from ListHead to access each file. This function supports wildcards\r
1e6e84c7 1540 and will process '?' and '*' as such. the list must be freed with a call to\r
94b17fa1 1541 ShellCloseFileMetaArg().\r
1542\r
1e6e84c7 1543 If you are NOT appending to an existing list *ListHead must be NULL. If\r
5f7431d0 1544 *ListHead is NULL then it must be callee freed.\r
94b17fa1 1545\r
1546 @param Arg pointer to path string\r
1547 @param OpenMode mode to open files with\r
1548 @param ListHead head of linked list of results\r
1549\r
1e6e84c7 1550 @retval EFI_SUCCESS the operation was sucessful and the list head\r
94b17fa1 1551 contains the list of opened files\r
94b17fa1 1552 @return != EFI_SUCCESS the operation failed\r
1553\r
1554 @sa InternalShellConvertFileListType\r
1555**/\r
1556EFI_STATUS\r
1557EFIAPI\r
1558ShellOpenFileMetaArg (\r
1559 IN CHAR16 *Arg,\r
1560 IN UINT64 OpenMode,\r
1561 IN OUT EFI_SHELL_FILE_INFO **ListHead\r
1562 )\r
1563{\r
1564 EFI_STATUS Status;\r
9b3bf083 1565 LIST_ENTRY mOldStyleFileList;\r
0960ba17 1566 CHAR16 *CleanFilePathStr;\r
1e6e84c7 1567\r
94b17fa1 1568 //\r
1569 // ASSERT that Arg and ListHead are not NULL\r
1570 //\r
1571 ASSERT(Arg != NULL);\r
1572 ASSERT(ListHead != NULL);\r
1573\r
715096c2
QS
1574 CleanFilePathStr = NULL;\r
1575\r
0960ba17
QS
1576 Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);\r
1577 if (EFI_ERROR (Status)) {\r
1578 return Status;\r
1579 }\r
1580\r
1e6e84c7 1581 //\r
94b17fa1 1582 // Check for UEFI Shell 2.0 protocols\r
1583 //\r
366f81a0 1584 if (gEfiShellProtocol != NULL) {\r
5f7431d0 1585 if (*ListHead == NULL) {\r
1586 *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
1587 if (*ListHead == NULL) {\r
0960ba17 1588 FreePool(CleanFilePathStr);\r
5f7431d0 1589 return (EFI_OUT_OF_RESOURCES);\r
1590 }\r
1591 InitializeListHead(&((*ListHead)->Link));\r
1e6e84c7 1592 }\r
0960ba17 1593 Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr,\r
1e6e84c7 1594 OpenMode,\r
2247dde4 1595 ListHead);\r
1596 if (EFI_ERROR(Status)) {\r
366f81a0 1597 gEfiShellProtocol->RemoveDupInFileList(ListHead);\r
2247dde4 1598 } else {\r
366f81a0 1599 Status = gEfiShellProtocol->RemoveDupInFileList(ListHead);\r
2247dde4 1600 }\r
a405b86d 1601 if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) {\r
1602 FreePool(*ListHead);\r
0960ba17 1603 FreePool(CleanFilePathStr);\r
a405b86d 1604 *ListHead = NULL;\r
1605 return (EFI_NOT_FOUND);\r
1606 }\r
0960ba17 1607 FreePool(CleanFilePathStr);\r
2247dde4 1608 return (Status);\r
1e6e84c7 1609 }\r
94b17fa1 1610\r
1611 //\r
92a5447e 1612 // Check for EFI shell\r
94b17fa1 1613 //\r
92a5447e 1614 if (mEfiShellEnvironment2 != NULL) {\r
1615 //\r
1616 // make sure the list head is initialized\r
1617 //\r
1618 InitializeListHead(&mOldStyleFileList);\r
94b17fa1 1619\r
92a5447e 1620 //\r
1621 // Get the EFI Shell list of files\r
1622 //\r
0960ba17 1623 Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList);\r
92a5447e 1624 if (EFI_ERROR(Status)) {\r
1625 *ListHead = NULL;\r
0960ba17 1626 FreePool(CleanFilePathStr);\r
92a5447e 1627 return (Status);\r
1628 }\r
94b17fa1 1629\r
9b3bf083 1630 if (*ListHead == NULL) {\r
92a5447e 1631 *ListHead = (EFI_SHELL_FILE_INFO *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
1632 if (*ListHead == NULL) {\r
0960ba17 1633 FreePool(CleanFilePathStr);\r
92a5447e 1634 return (EFI_OUT_OF_RESOURCES);\r
1635 }\r
1636 InitializeListHead(&((*ListHead)->Link));\r
9b3bf083 1637 }\r
9b3bf083 1638\r
92a5447e 1639 //\r
1640 // Convert that to equivalent of UEFI Shell 2.0 structure\r
1641 //\r
1642 InternalShellConvertFileListType(&mOldStyleFileList, &(*ListHead)->Link);\r
94b17fa1 1643\r
92a5447e 1644 //\r
1645 // Free the EFI Shell version that was converted.\r
1646 //\r
1647 mEfiShellEnvironment2->FreeFileList(&mOldStyleFileList);\r
94b17fa1 1648\r
92a5447e 1649 if ((*ListHead)->Link.ForwardLink == (*ListHead)->Link.BackLink && (*ListHead)->Link.BackLink == &((*ListHead)->Link)) {\r
1650 FreePool(*ListHead);\r
1651 *ListHead = NULL;\r
1652 Status = EFI_NOT_FOUND;\r
1653 }\r
0960ba17 1654 FreePool(CleanFilePathStr);\r
92a5447e 1655 return (Status);\r
a405b86d 1656 }\r
1657\r
0960ba17 1658 FreePool(CleanFilePathStr);\r
92a5447e 1659 return (EFI_UNSUPPORTED);\r
94b17fa1 1660}\r
1661/**\r
a405b86d 1662 Free the linked list returned from ShellOpenFileMetaArg.\r
94b17fa1 1663\r
a405b86d 1664 if ListHead is NULL then ASSERT().\r
94b17fa1 1665\r
a405b86d 1666 @param ListHead the pointer to free.\r
94b17fa1 1667\r
a405b86d 1668 @retval EFI_SUCCESS the operation was sucessful.\r
94b17fa1 1669**/\r
1670EFI_STATUS\r
1671EFIAPI\r
1672ShellCloseFileMetaArg (\r
1673 IN OUT EFI_SHELL_FILE_INFO **ListHead\r
1674 )\r
1675{\r
1676 LIST_ENTRY *Node;\r
1677\r
1678 //\r
1679 // ASSERT that ListHead is not NULL\r
1680 //\r
1681 ASSERT(ListHead != NULL);\r
1682\r
1e6e84c7 1683 //\r
94b17fa1 1684 // Check for UEFI Shell 2.0 protocols\r
1685 //\r
366f81a0 1686 if (gEfiShellProtocol != NULL) {\r
1687 return (gEfiShellProtocol->FreeFileList(ListHead));\r
92a5447e 1688 } else if (mEfiShellEnvironment2 != NULL) {\r
94b17fa1 1689 //\r
1e6e84c7 1690 // Since this is EFI Shell version we need to free our internally made copy\r
94b17fa1 1691 // of the list\r
1692 //\r
1e6e84c7 1693 for ( Node = GetFirstNode(&(*ListHead)->Link)\r
a405b86d 1694 ; *ListHead != NULL && !IsListEmpty(&(*ListHead)->Link)\r
9b3bf083 1695 ; Node = GetFirstNode(&(*ListHead)->Link)) {\r
94b17fa1 1696 RemoveEntryList(Node);\r
a405b86d 1697 ((EFI_FILE_PROTOCOL*)((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle)->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle);\r
94b17fa1 1698 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);\r
1699 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName);\r
1700 FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);\r
1701 FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);\r
1702 }\r
75a5e2ef 1703 SHELL_FREE_NON_NULL(*ListHead);\r
94b17fa1 1704 return EFI_SUCCESS;\r
1705 }\r
92a5447e 1706\r
1707 return (EFI_UNSUPPORTED);\r
94b17fa1 1708}\r
1709\r
125c2cf4 1710/**\r
1711 Find a file by searching the CWD and then the path.\r
1712\r
b3011f40 1713 If FileName is NULL then ASSERT.\r
125c2cf4 1714\r
b3011f40 1715 If the return value is not NULL then the memory must be caller freed.\r
125c2cf4 1716\r
1717 @param FileName Filename string.\r
1718\r
1719 @retval NULL the file was not found\r
1720 @return !NULL the full path to the file.\r
1721**/\r
1722CHAR16 *\r
1723EFIAPI\r
1724ShellFindFilePath (\r
1725 IN CONST CHAR16 *FileName\r
1726 )\r
1727{\r
1728 CONST CHAR16 *Path;\r
a405b86d 1729 SHELL_FILE_HANDLE Handle;\r
125c2cf4 1730 EFI_STATUS Status;\r
1731 CHAR16 *RetVal;\r
1732 CHAR16 *TestPath;\r
1733 CONST CHAR16 *Walker;\r
36a9d672 1734 UINTN Size;\r
1cd45e78 1735 CHAR16 *TempChar;\r
125c2cf4 1736\r
1737 RetVal = NULL;\r
1738\r
a405b86d 1739 //\r
1740 // First make sure its not an absolute path.\r
1741 //\r
1742 Status = ShellOpenFileByName(FileName, &Handle, EFI_FILE_MODE_READ, 0);\r
1743 if (!EFI_ERROR(Status)){\r
1744 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
1745 ASSERT(RetVal == NULL);\r
1746 RetVal = StrnCatGrow(&RetVal, NULL, FileName, 0);\r
1747 ShellCloseFile(&Handle);\r
1748 return (RetVal);\r
1749 } else {\r
1750 ShellCloseFile(&Handle);\r
1751 }\r
1752 }\r
1753\r
125c2cf4 1754 Path = ShellGetEnvironmentVariable(L"cwd");\r
1755 if (Path != NULL) {\r
fbd2dfad 1756 Size = StrSize(Path) + sizeof(CHAR16);\r
36a9d672 1757 Size += StrSize(FileName);\r
1758 TestPath = AllocateZeroPool(Size);\r
c9d92df0 1759 if (TestPath == NULL) {\r
1760 return (NULL);\r
1761 }\r
e75390f0 1762 StrCpyS(TestPath, Size/sizeof(CHAR16), Path);\r
fbd2dfad 1763 StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");\r
e75390f0 1764 StrCatS(TestPath, Size/sizeof(CHAR16), FileName);\r
125c2cf4 1765 Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
1766 if (!EFI_ERROR(Status)){\r
a405b86d 1767 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
1768 ASSERT(RetVal == NULL);\r
1769 RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);\r
1770 ShellCloseFile(&Handle);\r
1771 FreePool(TestPath);\r
1772 return (RetVal);\r
1773 } else {\r
1774 ShellCloseFile(&Handle);\r
1775 }\r
125c2cf4 1776 }\r
1777 FreePool(TestPath);\r
1778 }\r
1779 Path = ShellGetEnvironmentVariable(L"path");\r
1780 if (Path != NULL) {\r
a405b86d 1781 Size = StrSize(Path)+sizeof(CHAR16);\r
36a9d672 1782 Size += StrSize(FileName);\r
1783 TestPath = AllocateZeroPool(Size);\r
3e082d58 1784 if (TestPath == NULL) {\r
1785 return (NULL);\r
1786 }\r
1e6e84c7 1787 Walker = (CHAR16*)Path;\r
125c2cf4 1788 do {\r
1789 CopyMem(TestPath, Walker, StrSize(Walker));\r
3e082d58 1790 if (TestPath != NULL) {\r
1791 TempChar = StrStr(TestPath, L";");\r
1792 if (TempChar != NULL) {\r
1793 *TempChar = CHAR_NULL;\r
1794 }\r
1795 if (TestPath[StrLen(TestPath)-1] != L'\\') {\r
e75390f0 1796 StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");\r
3e082d58 1797 }\r
89e8537a 1798 if (FileName[0] == L'\\') {\r
1799 FileName++;\r
1800 }\r
e75390f0 1801 StrCatS(TestPath, Size/sizeof(CHAR16), FileName);\r
3e082d58 1802 if (StrStr(Walker, L";") != NULL) {\r
1803 Walker = StrStr(Walker, L";") + 1;\r
a405b86d 1804 } else {\r
3e082d58 1805 Walker = NULL;\r
1806 }\r
1807 Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
1808 if (!EFI_ERROR(Status)){\r
1809 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
1810 ASSERT(RetVal == NULL);\r
1811 RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);\r
1812 ShellCloseFile(&Handle);\r
1813 break;\r
1814 } else {\r
1815 ShellCloseFile(&Handle);\r
1816 }\r
a405b86d 1817 }\r
125c2cf4 1818 }\r
1819 } while (Walker != NULL && Walker[0] != CHAR_NULL);\r
1820 FreePool(TestPath);\r
1821 }\r
1822 return (RetVal);\r
1823}\r
1824\r
b3011f40 1825/**\r
1e6e84c7 1826 Find a file by searching the CWD and then the path with a variable set of file\r
1827 extensions. If the file is not found it will append each extension in the list\r
b3011f40 1828 in the order provided and return the first one that is successful.\r
1829\r
1830 If FileName is NULL, then ASSERT.\r
1831 If FileExtension is NULL, then behavior is identical to ShellFindFilePath.\r
1832\r
1833 If the return value is not NULL then the memory must be caller freed.\r
1834\r
1835 @param[in] FileName Filename string.\r
1836 @param[in] FileExtension Semi-colon delimeted list of possible extensions.\r
1837\r
1838 @retval NULL The file was not found.\r
1839 @retval !NULL The path to the file.\r
1840**/\r
1841CHAR16 *\r
1842EFIAPI\r
1843ShellFindFilePathEx (\r
1844 IN CONST CHAR16 *FileName,\r
1845 IN CONST CHAR16 *FileExtension\r
1846 )\r
1847{\r
1848 CHAR16 *TestPath;\r
1849 CHAR16 *RetVal;\r
1850 CONST CHAR16 *ExtensionWalker;\r
9e926b69 1851 UINTN Size;\r
1cd45e78 1852 CHAR16 *TempChar;\r
c9d92df0 1853 CHAR16 *TempChar2;\r
1cd45e78 1854\r
b3011f40 1855 ASSERT(FileName != NULL);\r
1856 if (FileExtension == NULL) {\r
1857 return (ShellFindFilePath(FileName));\r
1858 }\r
1859 RetVal = ShellFindFilePath(FileName);\r
1860 if (RetVal != NULL) {\r
1861 return (RetVal);\r
1862 }\r
9e926b69 1863 Size = StrSize(FileName);\r
1864 Size += StrSize(FileExtension);\r
1865 TestPath = AllocateZeroPool(Size);\r
c9d92df0 1866 if (TestPath == NULL) {\r
1867 return (NULL);\r
1868 }\r
a405b86d 1869 for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension; TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){\r
e75390f0 1870 StrCpyS(TestPath, Size/sizeof(CHAR16), FileName);\r
a405b86d 1871 if (ExtensionWalker != NULL) {\r
e75390f0 1872 StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker);\r
a405b86d 1873 }\r
1cd45e78 1874 TempChar = StrStr(TestPath, L";");\r
1875 if (TempChar != NULL) {\r
1876 *TempChar = CHAR_NULL;\r
b3011f40 1877 }\r
1878 RetVal = ShellFindFilePath(TestPath);\r
1879 if (RetVal != NULL) {\r
1880 break;\r
1881 }\r
a405b86d 1882 ASSERT(ExtensionWalker != NULL);\r
c9d92df0 1883 TempChar2 = StrStr(ExtensionWalker, L";");\r
b3011f40 1884 }\r
1885 FreePool(TestPath);\r
1886 return (RetVal);\r
1887}\r
1888\r
94b17fa1 1889typedef struct {\r
9b3bf083 1890 LIST_ENTRY Link;\r
94b17fa1 1891 CHAR16 *Name;\r
a405b86d 1892 SHELL_PARAM_TYPE Type;\r
94b17fa1 1893 CHAR16 *Value;\r
1894 UINTN OriginalPosition;\r
1895} SHELL_PARAM_PACKAGE;\r
1896\r
1897/**\r
1e6e84c7 1898 Checks the list of valid arguments and returns TRUE if the item was found. If the\r
94b17fa1 1899 return value is TRUE then the type parameter is set also.\r
1e6e84c7 1900\r
94b17fa1 1901 if CheckList is NULL then ASSERT();\r
1902 if Name is NULL then ASSERT();\r
1903 if Type is NULL then ASSERT();\r
1904\r
94b17fa1 1905 @param Name pointer to Name of parameter found\r
1906 @param CheckList List to check against\r
a405b86d 1907 @param Type pointer to type of parameter if it was found\r
94b17fa1 1908\r
1909 @retval TRUE the Parameter was found. Type is valid.\r
1910 @retval FALSE the Parameter was not found. Type is not valid.\r
1911**/\r
1912BOOLEAN\r
d2b4564b 1913InternalIsOnCheckList (\r
94b17fa1 1914 IN CONST CHAR16 *Name,\r
1915 IN CONST SHELL_PARAM_ITEM *CheckList,\r
252d9457 1916 OUT SHELL_PARAM_TYPE *Type\r
a405b86d 1917 )\r
1918{\r
94b17fa1 1919 SHELL_PARAM_ITEM *TempListItem;\r
252d9457 1920 CHAR16 *TempString;\r
94b17fa1 1921\r
1922 //\r
1923 // ASSERT that all 3 pointer parameters aren't NULL\r
1924 //\r
1925 ASSERT(CheckList != NULL);\r
1926 ASSERT(Type != NULL);\r
1927 ASSERT(Name != NULL);\r
1928\r
d2b4564b 1929 //\r
1930 // question mark and page break mode are always supported\r
1931 //\r
1932 if ((StrCmp(Name, L"-?") == 0) ||\r
1933 (StrCmp(Name, L"-b") == 0)\r
a405b86d 1934 ) {\r
252d9457 1935 *Type = TypeFlag;\r
d2b4564b 1936 return (TRUE);\r
1937 }\r
1938\r
94b17fa1 1939 //\r
1940 // Enumerate through the list\r
1941 //\r
1942 for (TempListItem = (SHELL_PARAM_ITEM*)CheckList ; TempListItem->Name != NULL ; TempListItem++) {\r
1943 //\r
9eb53ac3 1944 // If the Type is TypeStart only check the first characters of the passed in param\r
1945 // If it matches set the type and return TRUE\r
94b17fa1 1946 //\r
b0934ac4 1947 if (TempListItem->Type == TypeStart) {\r
252d9457 1948 if (StrnCmp(Name, TempListItem->Name, StrLen(TempListItem->Name)) == 0) {\r
1949 *Type = TempListItem->Type;\r
1950 return (TRUE);\r
1951 }\r
1952 TempString = NULL;\r
1953 TempString = StrnCatGrow(&TempString, NULL, Name, StrLen(TempListItem->Name));\r
1954 if (TempString != NULL) {\r
1955 if (StringNoCaseCompare(&TempString, &TempListItem->Name) == 0) {\r
1956 *Type = TempListItem->Type;\r
1957 FreePool(TempString);\r
1958 return (TRUE);\r
1959 }\r
1960 FreePool(TempString);\r
1961 }\r
1962 } else if (StringNoCaseCompare(&Name, &TempListItem->Name) == 0) {\r
94b17fa1 1963 *Type = TempListItem->Type;\r
1964 return (TRUE);\r
1965 }\r
1966 }\r
2247dde4 1967\r
94b17fa1 1968 return (FALSE);\r
1969}\r
1970/**\r
d2b4564b 1971 Checks the string for indicators of "flag" status. this is a leading '/', '-', or '+'\r
94b17fa1 1972\r
a405b86d 1973 @param[in] Name pointer to Name of parameter found\r
1974 @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.\r
658bf43e 1975 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.\r
94b17fa1 1976\r
1977 @retval TRUE the Parameter is a flag.\r
a405b86d 1978 @retval FALSE the Parameter not a flag.\r
94b17fa1 1979**/\r
1980BOOLEAN\r
d2b4564b 1981InternalIsFlag (\r
2247dde4 1982 IN CONST CHAR16 *Name,\r
658bf43e 1983 IN CONST BOOLEAN AlwaysAllowNumbers,\r
1984 IN CONST BOOLEAN TimeNumbers\r
94b17fa1 1985 )\r
1986{\r
1987 //\r
1988 // ASSERT that Name isn't NULL\r
1989 //\r
1990 ASSERT(Name != NULL);\r
1991\r
2247dde4 1992 //\r
1993 // If we accept numbers then dont return TRUE. (they will be values)\r
1994 //\r
658bf43e 1995 if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {\r
2247dde4 1996 return (FALSE);\r
1997 }\r
1998\r
94b17fa1 1999 //\r
a405b86d 2000 // If the Name has a /, +, or - as the first character return TRUE\r
94b17fa1 2001 //\r
1e6e84c7 2002 if ((Name[0] == L'/') ||\r
d2b4564b 2003 (Name[0] == L'-') ||\r
2004 (Name[0] == L'+')\r
a405b86d 2005 ) {\r
94b17fa1 2006 return (TRUE);\r
2007 }\r
2008 return (FALSE);\r
2009}\r
2010\r
2011/**\r
1e6e84c7 2012 Checks the command line arguments passed against the list of valid ones.\r
94b17fa1 2013\r
2014 If no initialization is required, then return RETURN_SUCCESS.\r
1e6e84c7 2015\r
a405b86d 2016 @param[in] CheckList pointer to list of parameters to check\r
2017 @param[out] CheckPackage pointer to pointer to list checked values\r
2018 @param[out] ProblemParam optional pointer to pointer to unicode string for\r
d2b4564b 2019 the paramater that caused failure. If used then the\r
2020 caller is responsible for freeing the memory.\r
a405b86d 2021 @param[in] AutoPageBreak will automatically set PageBreakEnabled for "b" parameter\r
2022 @param[in] Argv pointer to array of parameters\r
2023 @param[in] Argc Count of parameters in Argv\r
2024 @param[in] AlwaysAllowNumbers TRUE to allow numbers always, FALSE otherwise.\r
94b17fa1 2025\r
2026 @retval EFI_SUCCESS The operation completed sucessfully.\r
2027 @retval EFI_OUT_OF_RESOURCES A memory allocation failed\r
2028 @retval EFI_INVALID_PARAMETER A parameter was invalid\r
1e6e84c7 2029 @retval EFI_VOLUME_CORRUPTED the command line was corrupt. an argument was\r
2030 duplicated. the duplicated command line argument\r
94b17fa1 2031 was returned in ProblemParam if provided.\r
1e6e84c7 2032 @retval EFI_NOT_FOUND a argument required a value that was missing.\r
94b17fa1 2033 the invalid command line argument was returned in\r
2034 ProblemParam if provided.\r
2035**/\r
2036EFI_STATUS\r
94b17fa1 2037InternalCommandLineParse (\r
2038 IN CONST SHELL_PARAM_ITEM *CheckList,\r
2039 OUT LIST_ENTRY **CheckPackage,\r
2040 OUT CHAR16 **ProblemParam OPTIONAL,\r
2041 IN BOOLEAN AutoPageBreak,\r
2042 IN CONST CHAR16 **Argv,\r
2247dde4 2043 IN UINTN Argc,\r
2044 IN BOOLEAN AlwaysAllowNumbers\r
a405b86d 2045 )\r
2046{\r
94b17fa1 2047 UINTN LoopCounter;\r
252d9457 2048 SHELL_PARAM_TYPE CurrentItemType;\r
94b17fa1 2049 SHELL_PARAM_PACKAGE *CurrentItemPackage;\r
125c2cf4 2050 UINTN GetItemValue;\r
2051 UINTN ValueSize;\r
a405b86d 2052 UINTN Count;\r
252d9457 2053 CONST CHAR16 *TempPointer;\r
98c16be5 2054 UINTN CurrentValueSize;\r
2efafabf 2055 CHAR16 *NewValue;\r
94b17fa1 2056\r
2057 CurrentItemPackage = NULL;\r
125c2cf4 2058 GetItemValue = 0;\r
2059 ValueSize = 0;\r
a405b86d 2060 Count = 0;\r
94b17fa1 2061\r
2062 //\r
2063 // If there is only 1 item we dont need to do anything\r
2064 //\r
a405b86d 2065 if (Argc < 1) {\r
94b17fa1 2066 *CheckPackage = NULL;\r
2067 return (EFI_SUCCESS);\r
2068 }\r
2069\r
2247dde4 2070 //\r
2071 // ASSERTs\r
2072 //\r
2073 ASSERT(CheckList != NULL);\r
2074 ASSERT(Argv != NULL);\r
2075\r
94b17fa1 2076 //\r
2077 // initialize the linked list\r
2078 //\r
2079 *CheckPackage = (LIST_ENTRY*)AllocateZeroPool(sizeof(LIST_ENTRY));\r
02a758cb 2080 if (*CheckPackage == NULL) {\r
beab0fc5 2081 return (EFI_OUT_OF_RESOURCES);\r
02a758cb 2082 }\r
beab0fc5 2083\r
94b17fa1 2084 InitializeListHead(*CheckPackage);\r
2085\r
2086 //\r
2087 // loop through each of the arguments\r
2088 //\r
2089 for (LoopCounter = 0 ; LoopCounter < Argc ; ++LoopCounter) {\r
2090 if (Argv[LoopCounter] == NULL) {\r
2091 //\r
2092 // do nothing for NULL argv\r
2093 //\r
a405b86d 2094 } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType)) {\r
2247dde4 2095 //\r
2096 // We might have leftover if last parameter didnt have optional value\r
2097 //\r
125c2cf4 2098 if (GetItemValue != 0) {\r
2099 GetItemValue = 0;\r
2247dde4 2100 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
2101 }\r
94b17fa1 2102 //\r
2103 // this is a flag\r
2104 //\r
252d9457 2105 CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));\r
beab0fc5 2106 if (CurrentItemPackage == NULL) {\r
2107 ShellCommandLineFreeVarList(*CheckPackage);\r
2108 *CheckPackage = NULL;\r
2109 return (EFI_OUT_OF_RESOURCES);\r
2110 }\r
98c16be5 2111 CurrentItemPackage->Name = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);\r
beab0fc5 2112 if (CurrentItemPackage->Name == NULL) {\r
2113 ShellCommandLineFreeVarList(*CheckPackage);\r
2114 *CheckPackage = NULL;\r
2115 return (EFI_OUT_OF_RESOURCES);\r
2116 }\r
94b17fa1 2117 CurrentItemPackage->Type = CurrentItemType;\r
2118 CurrentItemPackage->OriginalPosition = (UINTN)(-1);\r
b1f95a06 2119 CurrentItemPackage->Value = NULL;\r
94b17fa1 2120\r
2121 //\r
2122 // Does this flag require a value\r
2123 //\r
125c2cf4 2124 switch (CurrentItemPackage->Type) {\r
94b17fa1 2125 //\r
125c2cf4 2126 // possibly trigger the next loop(s) to populate the value of this item\r
1e6e84c7 2127 //\r
125c2cf4 2128 case TypeValue:\r
658bf43e 2129 case TypeTimeValue:\r
1e6e84c7 2130 GetItemValue = 1;\r
125c2cf4 2131 ValueSize = 0;\r
2132 break;\r
2133 case TypeDoubleValue:\r
2134 GetItemValue = 2;\r
2135 ValueSize = 0;\r
2136 break;\r
2137 case TypeMaxValue:\r
2138 GetItemValue = (UINTN)(-1);\r
2139 ValueSize = 0;\r
2140 break;\r
2141 default:\r
2142 //\r
2143 // this item has no value expected; we are done\r
2144 //\r
2145 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
2146 ASSERT(GetItemValue == 0);\r
2147 break;\r
94b17fa1 2148 }\r
af7a3a54 2149 } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {\r
b1f95a06 2150 //\r
125c2cf4 2151 // get the item VALUE for a previous flag\r
b1f95a06 2152 //\r
484dd08c 2153 CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
2efafabf
RN
2154 NewValue = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);\r
2155 if (NewValue == NULL) {\r
2156 SHELL_FREE_NON_NULL (CurrentItemPackage->Value);\r
2157 SHELL_FREE_NON_NULL (CurrentItemPackage);\r
2158 ShellCommandLineFreeVarList (*CheckPackage);\r
2159 *CheckPackage = NULL;\r
2160 return EFI_OUT_OF_RESOURCES;\r
2161 }\r
2162 CurrentItemPackage->Value = NewValue;\r
484dd08c 2163 if (ValueSize == 0) {\r
ba0014b9
LG
2164 StrCpyS( CurrentItemPackage->Value,\r
2165 CurrentValueSize/sizeof(CHAR16),\r
e75390f0
QS
2166 Argv[LoopCounter]\r
2167 );\r
125c2cf4 2168 } else {\r
ba0014b9
LG
2169 StrCatS( CurrentItemPackage->Value,\r
2170 CurrentValueSize/sizeof(CHAR16),\r
e75390f0
QS
2171 L" "\r
2172 );\r
ba0014b9
LG
2173 StrCatS( CurrentItemPackage->Value,\r
2174 CurrentValueSize/sizeof(CHAR16),\r
e75390f0
QS
2175 Argv[LoopCounter]\r
2176 );\r
125c2cf4 2177 }\r
484dd08c 2178 ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
ba0014b9 2179\r
125c2cf4 2180 GetItemValue--;\r
2181 if (GetItemValue == 0) {\r
2182 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
2183 }\r
658bf43e 2184 } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){\r
b1f95a06 2185 //\r
2186 // add this one as a non-flag\r
2187 //\r
252d9457 2188\r
2189 TempPointer = Argv[LoopCounter];\r
b0934ac4 2190 if ((*TempPointer == L'^' && *(TempPointer+1) == L'-')\r
252d9457 2191 || (*TempPointer == L'^' && *(TempPointer+1) == L'/')\r
2192 || (*TempPointer == L'^' && *(TempPointer+1) == L'+')\r
2193 ){\r
2194 TempPointer++;\r
2195 }\r
2196 CurrentItemPackage = AllocateZeroPool(sizeof(SHELL_PARAM_PACKAGE));\r
beab0fc5 2197 if (CurrentItemPackage == NULL) {\r
2198 ShellCommandLineFreeVarList(*CheckPackage);\r
2199 *CheckPackage = NULL;\r
2200 return (EFI_OUT_OF_RESOURCES);\r
2201 }\r
b1f95a06 2202 CurrentItemPackage->Name = NULL;\r
2203 CurrentItemPackage->Type = TypePosition;\r
98c16be5 2204 CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);\r
beab0fc5 2205 if (CurrentItemPackage->Value == NULL) {\r
2206 ShellCommandLineFreeVarList(*CheckPackage);\r
2207 *CheckPackage = NULL;\r
2208 return (EFI_OUT_OF_RESOURCES);\r
2209 }\r
a405b86d 2210 CurrentItemPackage->OriginalPosition = Count++;\r
9b3bf083 2211 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
252d9457 2212 } else {\r
94b17fa1 2213 //\r
2214 // this was a non-recognised flag... error!\r
2215 //\r
252d9457 2216 if (ProblemParam != NULL) {\r
98c16be5 2217 *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);\r
252d9457 2218 }\r
94b17fa1 2219 ShellCommandLineFreeVarList(*CheckPackage);\r
2220 *CheckPackage = NULL;\r
2221 return (EFI_VOLUME_CORRUPTED);\r
94b17fa1 2222 }\r
2223 }\r
125c2cf4 2224 if (GetItemValue != 0) {\r
2225 GetItemValue = 0;\r
2226 InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
2227 }\r
94b17fa1 2228 //\r
2229 // support for AutoPageBreak\r
2230 //\r
2231 if (AutoPageBreak && ShellCommandLineGetFlag(*CheckPackage, L"-b")) {\r
2232 ShellSetPageBreakMode(TRUE);\r
2233 }\r
2234 return (EFI_SUCCESS);\r
2235}\r
2236\r
2237/**\r
1e6e84c7 2238 Checks the command line arguments passed against the list of valid ones.\r
94b17fa1 2239 Optionally removes NULL values first.\r
1e6e84c7 2240\r
94b17fa1 2241 If no initialization is required, then return RETURN_SUCCESS.\r
1e6e84c7 2242\r
a405b86d 2243 @param[in] CheckList The pointer to list of parameters to check.\r
2244 @param[out] CheckPackage The package of checked values.\r
2245 @param[out] ProblemParam Optional pointer to pointer to unicode string for\r
94b17fa1 2246 the paramater that caused failure.\r
a405b86d 2247 @param[in] AutoPageBreak Will automatically set PageBreakEnabled.\r
2248 @param[in] AlwaysAllowNumbers Will never fail for number based flags.\r
94b17fa1 2249\r
2250 @retval EFI_SUCCESS The operation completed sucessfully.\r
a405b86d 2251 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
2252 @retval EFI_INVALID_PARAMETER A parameter was invalid.\r
2253 @retval EFI_VOLUME_CORRUPTED The command line was corrupt.\r
2254 @retval EFI_DEVICE_ERROR The commands contained 2 opposing arguments. One\r
1e6e84c7 2255 of the command line arguments was returned in\r
94b17fa1 2256 ProblemParam if provided.\r
a405b86d 2257 @retval EFI_NOT_FOUND A argument required a value that was missing.\r
2258 The invalid command line argument was returned in\r
94b17fa1 2259 ProblemParam if provided.\r
2260**/\r
2261EFI_STATUS\r
2262EFIAPI\r
2247dde4 2263ShellCommandLineParseEx (\r
94b17fa1 2264 IN CONST SHELL_PARAM_ITEM *CheckList,\r
2265 OUT LIST_ENTRY **CheckPackage,\r
2266 OUT CHAR16 **ProblemParam OPTIONAL,\r
2247dde4 2267 IN BOOLEAN AutoPageBreak,\r
2268 IN BOOLEAN AlwaysAllowNumbers\r
a405b86d 2269 )\r
2270{\r
1e6e84c7 2271 //\r
94b17fa1 2272 // ASSERT that CheckList and CheckPackage aren't NULL\r
2273 //\r
2274 ASSERT(CheckList != NULL);\r
2275 ASSERT(CheckPackage != NULL);\r
2276\r
1e6e84c7 2277 //\r
94b17fa1 2278 // Check for UEFI Shell 2.0 protocols\r
2279 //\r
366f81a0 2280 if (gEfiShellParametersProtocol != NULL) {\r
1e6e84c7 2281 return (InternalCommandLineParse(CheckList,\r
2282 CheckPackage,\r
2283 ProblemParam,\r
2284 AutoPageBreak,\r
366f81a0 2285 (CONST CHAR16**) gEfiShellParametersProtocol->Argv,\r
2286 gEfiShellParametersProtocol->Argc,\r
2247dde4 2287 AlwaysAllowNumbers));\r
94b17fa1 2288 }\r
2289\r
1e6e84c7 2290 //\r
94b17fa1 2291 // ASSERT That EFI Shell is not required\r
2292 //\r
2293 ASSERT (mEfiShellInterface != NULL);\r
1e6e84c7 2294 return (InternalCommandLineParse(CheckList,\r
2295 CheckPackage,\r
2296 ProblemParam,\r
2297 AutoPageBreak,\r
08d7f8e8 2298 (CONST CHAR16**) mEfiShellInterface->Argv,\r
2247dde4 2299 mEfiShellInterface->Argc,\r
2300 AlwaysAllowNumbers));\r
94b17fa1 2301}\r
2302\r
2303/**\r
2304 Frees shell variable list that was returned from ShellCommandLineParse.\r
2305\r
2306 This function will free all the memory that was used for the CheckPackage\r
2307 list of postprocessed shell arguments.\r
2308\r
2309 this function has no return value.\r
2310\r
2311 if CheckPackage is NULL, then return\r
2312\r
2313 @param CheckPackage the list to de-allocate\r
2314 **/\r
2315VOID\r
2316EFIAPI\r
2317ShellCommandLineFreeVarList (\r
2318 IN LIST_ENTRY *CheckPackage\r
a405b86d 2319 )\r
2320{\r
94b17fa1 2321 LIST_ENTRY *Node;\r
2322\r
2323 //\r
2324 // check for CheckPackage == NULL\r
2325 //\r
2326 if (CheckPackage == NULL) {\r
2327 return;\r
2328 }\r
2329\r
2330 //\r
2331 // for each node in the list\r
2332 //\r
9eb53ac3 2333 for ( Node = GetFirstNode(CheckPackage)\r
a405b86d 2334 ; !IsListEmpty(CheckPackage)\r
9eb53ac3 2335 ; Node = GetFirstNode(CheckPackage)\r
a405b86d 2336 ){\r
94b17fa1 2337 //\r
2338 // Remove it from the list\r
2339 //\r
2340 RemoveEntryList(Node);\r
2341\r
2342 //\r
2343 // if it has a name free the name\r
2344 //\r
2345 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {\r
2346 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Name);\r
2347 }\r
2348\r
2349 //\r
2350 // if it has a value free the value\r
2351 //\r
2352 if (((SHELL_PARAM_PACKAGE*)Node)->Value != NULL) {\r
2353 FreePool(((SHELL_PARAM_PACKAGE*)Node)->Value);\r
2354 }\r
1e6e84c7 2355\r
94b17fa1 2356 //\r
2357 // free the node structure\r
2358 //\r
2359 FreePool((SHELL_PARAM_PACKAGE*)Node);\r
2360 }\r
2361 //\r
2362 // free the list head node\r
2363 //\r
2364 FreePool(CheckPackage);\r
2365}\r
2366/**\r
2367 Checks for presence of a flag parameter\r
2368\r
2369 flag arguments are in the form of "-<Key>" or "/<Key>", but do not have a value following the key\r
2370\r
2371 if CheckPackage is NULL then return FALSE.\r
2372 if KeyString is NULL then ASSERT()\r
1e6e84c7 2373\r
94b17fa1 2374 @param CheckPackage The package of parsed command line arguments\r
2375 @param KeyString the Key of the command line argument to check for\r
2376\r
2377 @retval TRUE the flag is on the command line\r
2378 @retval FALSE the flag is not on the command line\r
2379 **/\r
2380BOOLEAN\r
2381EFIAPI\r
2382ShellCommandLineGetFlag (\r
a405b86d 2383 IN CONST LIST_ENTRY * CONST CheckPackage,\r
2384 IN CONST CHAR16 * CONST KeyString\r
2385 )\r
2386{\r
94b17fa1 2387 LIST_ENTRY *Node;\r
252d9457 2388 CHAR16 *TempString;\r
94b17fa1 2389\r
2390 //\r
0c1950ba 2391 // return FALSE for no package or KeyString is NULL\r
94b17fa1 2392 //\r
0c1950ba 2393 if (CheckPackage == NULL || KeyString == NULL) {\r
94b17fa1 2394 return (FALSE);\r
2395 }\r
2396\r
2397 //\r
2398 // enumerate through the list of parametrs\r
2399 //\r
1e6e84c7 2400 for ( Node = GetFirstNode(CheckPackage)\r
2401 ; !IsNull (CheckPackage, Node)\r
2402 ; Node = GetNextNode(CheckPackage, Node)\r
252d9457 2403 ){\r
94b17fa1 2404 //\r
2405 // If the Name matches, return TRUE (and there may be NULL name)\r
2406 //\r
2407 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {\r
9eb53ac3 2408 //\r
2409 // If Type is TypeStart then only compare the begining of the strings\r
2410 //\r
252d9457 2411 if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {\r
2412 if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {\r
2413 return (TRUE);\r
2414 }\r
2415 TempString = NULL;\r
2416 TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));\r
2417 if (TempString != NULL) {\r
2418 if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
2419 FreePool(TempString);\r
2420 return (TRUE);\r
2421 }\r
2422 FreePool(TempString);\r
2423 }\r
2424 } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
94b17fa1 2425 return (TRUE);\r
2426 }\r
2427 }\r
2428 }\r
2429 return (FALSE);\r
2430}\r
2431/**\r
a405b86d 2432 Returns value from command line argument.\r
94b17fa1 2433\r
a405b86d 2434 Value parameters are in the form of "-<Key> value" or "/<Key> value".\r
1e6e84c7 2435\r
a405b86d 2436 If CheckPackage is NULL, then return NULL.\r
94b17fa1 2437\r
a405b86d 2438 @param[in] CheckPackage The package of parsed command line arguments.\r
2439 @param[in] KeyString The Key of the command line argument to check for.\r
94b17fa1 2440\r
a405b86d 2441 @retval NULL The flag is not on the command line.\r
2442 @retval !=NULL The pointer to unicode string of the value.\r
2443**/\r
94b17fa1 2444CONST CHAR16*\r
2445EFIAPI\r
2446ShellCommandLineGetValue (\r
2447 IN CONST LIST_ENTRY *CheckPackage,\r
2448 IN CHAR16 *KeyString\r
a405b86d 2449 )\r
2450{\r
94b17fa1 2451 LIST_ENTRY *Node;\r
252d9457 2452 CHAR16 *TempString;\r
94b17fa1 2453\r
2454 //\r
0c1950ba 2455 // return NULL for no package or KeyString is NULL\r
94b17fa1 2456 //\r
0c1950ba 2457 if (CheckPackage == NULL || KeyString == NULL) {\r
94b17fa1 2458 return (NULL);\r
2459 }\r
2460\r
2461 //\r
2462 // enumerate through the list of parametrs\r
2463 //\r
1e6e84c7 2464 for ( Node = GetFirstNode(CheckPackage)\r
2465 ; !IsNull (CheckPackage, Node)\r
2466 ; Node = GetNextNode(CheckPackage, Node)\r
252d9457 2467 ){\r
94b17fa1 2468 //\r
252d9457 2469 // If the Name matches, return TRUE (and there may be NULL name)\r
94b17fa1 2470 //\r
2471 if (((SHELL_PARAM_PACKAGE*)Node)->Name != NULL) {\r
9eb53ac3 2472 //\r
2473 // If Type is TypeStart then only compare the begining of the strings\r
2474 //\r
252d9457 2475 if (((SHELL_PARAM_PACKAGE*)Node)->Type == TypeStart) {\r
2476 if (StrnCmp(KeyString, ((SHELL_PARAM_PACKAGE*)Node)->Name, StrLen(KeyString)) == 0) {\r
2477 return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));\r
2478 }\r
2479 TempString = NULL;\r
2480 TempString = StrnCatGrow(&TempString, NULL, KeyString, StrLen(((SHELL_PARAM_PACKAGE*)Node)->Name));\r
2481 if (TempString != NULL) {\r
2482 if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
2483 FreePool(TempString);\r
2484 return (((SHELL_PARAM_PACKAGE*)Node)->Name + StrLen(KeyString));\r
2485 }\r
2486 FreePool(TempString);\r
2487 }\r
2488 } else if (StringNoCaseCompare(&KeyString, &((SHELL_PARAM_PACKAGE*)Node)->Name) == 0) {\r
94b17fa1 2489 return (((SHELL_PARAM_PACKAGE*)Node)->Value);\r
2490 }\r
2491 }\r
2492 }\r
2493 return (NULL);\r
2494}\r
a405b86d 2495\r
94b17fa1 2496/**\r
a405b86d 2497 Returns raw value from command line argument.\r
94b17fa1 2498\r
a405b86d 2499 Raw value parameters are in the form of "value" in a specific position in the list.\r
1e6e84c7 2500\r
a405b86d 2501 If CheckPackage is NULL, then return NULL.\r
94b17fa1 2502\r
a405b86d 2503 @param[in] CheckPackage The package of parsed command line arguments.\r
2504 @param[in] Position The position of the value.\r
94b17fa1 2505\r
a405b86d 2506 @retval NULL The flag is not on the command line.\r
2507 @retval !=NULL The pointer to unicode string of the value.\r
94b17fa1 2508 **/\r
2509CONST CHAR16*\r
2510EFIAPI\r
2511ShellCommandLineGetRawValue (\r
a405b86d 2512 IN CONST LIST_ENTRY * CONST CheckPackage,\r
2513 IN UINTN Position\r
2514 )\r
2515{\r
94b17fa1 2516 LIST_ENTRY *Node;\r
2517\r
2518 //\r
2519 // check for CheckPackage == NULL\r
2520 //\r
2521 if (CheckPackage == NULL) {\r
2522 return (NULL);\r
2523 }\r
2524\r
2525 //\r
2526 // enumerate through the list of parametrs\r
2527 //\r
1e6e84c7 2528 for ( Node = GetFirstNode(CheckPackage)\r
2529 ; !IsNull (CheckPackage, Node)\r
2530 ; Node = GetNextNode(CheckPackage, Node)\r
a405b86d 2531 ){\r
94b17fa1 2532 //\r
2533 // If the position matches, return the value\r
2534 //\r
2535 if (((SHELL_PARAM_PACKAGE*)Node)->OriginalPosition == Position) {\r
2536 return (((SHELL_PARAM_PACKAGE*)Node)->Value);\r
2537 }\r
2538 }\r
2539 return (NULL);\r
b1f95a06 2540}\r
2247dde4 2541\r
2542/**\r
1e6e84c7 2543 returns the number of command line value parameters that were parsed.\r
2544\r
2247dde4 2545 this will not include flags.\r
2546\r
a405b86d 2547 @param[in] CheckPackage The package of parsed command line arguments.\r
2548\r
2247dde4 2549 @retval (UINTN)-1 No parsing has ocurred\r
2550 @return other The number of value parameters found\r
2551**/\r
2552UINTN\r
2553EFIAPI\r
2554ShellCommandLineGetCount(\r
a405b86d 2555 IN CONST LIST_ENTRY *CheckPackage\r
125c2cf4 2556 )\r
2557{\r
a405b86d 2558 LIST_ENTRY *Node1;\r
2559 UINTN Count;\r
2560\r
2561 if (CheckPackage == NULL) {\r
2562 return (0);\r
2563 }\r
2564 for ( Node1 = GetFirstNode(CheckPackage), Count = 0\r
2565 ; !IsNull (CheckPackage, Node1)\r
2566 ; Node1 = GetNextNode(CheckPackage, Node1)\r
2567 ){\r
2568 if (((SHELL_PARAM_PACKAGE*)Node1)->Name == NULL) {\r
2569 Count++;\r
2570 }\r
2571 }\r
2572 return (Count);\r
2247dde4 2573}\r
2574\r
36a9d672 2575/**\r
cceb4ebd 2576 Determines if a parameter is duplicated.\r
36a9d672 2577\r
1e6e84c7 2578 If Param is not NULL then it will point to a callee allocated string buffer\r
36a9d672 2579 with the parameter value if a duplicate is found.\r
2580\r
2581 If CheckPackage is NULL, then ASSERT.\r
2582\r
2583 @param[in] CheckPackage The package of parsed command line arguments.\r
2584 @param[out] Param Upon finding one, a pointer to the duplicated parameter.\r
2585\r
2586 @retval EFI_SUCCESS No parameters were duplicated.\r
2587 @retval EFI_DEVICE_ERROR A duplicate was found.\r
2588 **/\r
2589EFI_STATUS\r
2590EFIAPI\r
2591ShellCommandLineCheckDuplicate (\r
2592 IN CONST LIST_ENTRY *CheckPackage,\r
2593 OUT CHAR16 **Param\r
2594 )\r
2595{\r
2596 LIST_ENTRY *Node1;\r
2597 LIST_ENTRY *Node2;\r
1e6e84c7 2598\r
36a9d672 2599 ASSERT(CheckPackage != NULL);\r
2600\r
1e6e84c7 2601 for ( Node1 = GetFirstNode(CheckPackage)\r
2602 ; !IsNull (CheckPackage, Node1)\r
2603 ; Node1 = GetNextNode(CheckPackage, Node1)\r
a405b86d 2604 ){\r
1e6e84c7 2605 for ( Node2 = GetNextNode(CheckPackage, Node1)\r
2606 ; !IsNull (CheckPackage, Node2)\r
2607 ; Node2 = GetNextNode(CheckPackage, Node2)\r
a405b86d 2608 ){\r
2609 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 2610 if (Param != NULL) {\r
2611 *Param = NULL;\r
2612 *Param = StrnCatGrow(Param, NULL, ((SHELL_PARAM_PACKAGE*)Node1)->Name, 0);\r
2613 }\r
2614 return (EFI_DEVICE_ERROR);\r
2615 }\r
2616 }\r
2617 }\r
2618 return (EFI_SUCCESS);\r
2619}\r
2620\r
975136ab 2621/**\r
1e6e84c7 2622 This is a find and replace function. Upon successful return the NewString is a copy of\r
975136ab 2623 SourceString with each instance of FindTarget replaced with ReplaceWith.\r
2624\r
b3011f40 2625 If SourceString and NewString overlap the behavior is undefined.\r
2626\r
975136ab 2627 If the string would grow bigger than NewSize it will halt and return error.\r
2628\r
4ff7e37b
ED
2629 @param[in] SourceString The string with source buffer.\r
2630 @param[in, out] NewString The string with resultant buffer.\r
2631 @param[in] NewSize The size in bytes of NewString.\r
2632 @param[in] FindTarget The string to look for.\r
2633 @param[in] ReplaceWith The string to replace FindTarget with.\r
2634 @param[in] SkipPreCarrot If TRUE will skip a FindTarget that has a '^'\r
2635 immediately before it.\r
2636 @param[in] ParameterReplacing If TRUE will add "" around items with spaces.\r
969c783b 2637\r
2638 @retval EFI_INVALID_PARAMETER SourceString was NULL.\r
2639 @retval EFI_INVALID_PARAMETER NewString was NULL.\r
2640 @retval EFI_INVALID_PARAMETER FindTarget was NULL.\r
2641 @retval EFI_INVALID_PARAMETER ReplaceWith was NULL.\r
2642 @retval EFI_INVALID_PARAMETER FindTarget had length < 1.\r
2643 @retval EFI_INVALID_PARAMETER SourceString had length < 1.\r
1e6e84c7 2644 @retval EFI_BUFFER_TOO_SMALL NewSize was less than the minimum size to hold\r
969c783b 2645 the new string (truncation occurred).\r
a405b86d 2646 @retval EFI_SUCCESS The string was successfully copied with replacement.\r
975136ab 2647**/\r
975136ab 2648EFI_STATUS\r
2649EFIAPI\r
a405b86d 2650ShellCopySearchAndReplace(\r
975136ab 2651 IN CHAR16 CONST *SourceString,\r
a405b86d 2652 IN OUT CHAR16 *NewString,\r
975136ab 2653 IN UINTN NewSize,\r
2654 IN CONST CHAR16 *FindTarget,\r
969c783b 2655 IN CONST CHAR16 *ReplaceWith,\r
a405b86d 2656 IN CONST BOOLEAN SkipPreCarrot,\r
2657 IN CONST BOOLEAN ParameterReplacing\r
1e6e84c7 2658 )\r
2247dde4 2659{\r
0158294b 2660 UINTN Size;\r
a405b86d 2661 CHAR16 *Replace;\r
2662\r
975136ab 2663 if ( (SourceString == NULL)\r
2664 || (NewString == NULL)\r
2665 || (FindTarget == NULL)\r
2666 || (ReplaceWith == NULL)\r
2667 || (StrLen(FindTarget) < 1)\r
2668 || (StrLen(SourceString) < 1)\r
a405b86d 2669 ){\r
975136ab 2670 return (EFI_INVALID_PARAMETER);\r
2671 }\r
a405b86d 2672 Replace = NULL;\r
2673 if (StrStr(ReplaceWith, L" ") == NULL || !ParameterReplacing) {\r
2674 Replace = StrnCatGrow(&Replace, NULL, ReplaceWith, 0);\r
2675 } else {\r
2676 Replace = AllocateZeroPool(StrSize(ReplaceWith) + 2*sizeof(CHAR16));\r
beab0fc5 2677 if (Replace != NULL) {\r
2678 UnicodeSPrint(Replace, StrSize(ReplaceWith) + 2*sizeof(CHAR16), L"\"%s\"", ReplaceWith);\r
2679 }\r
a405b86d 2680 }\r
3e082d58 2681 if (Replace == NULL) {\r
2682 return (EFI_OUT_OF_RESOURCES);\r
2683 }\r
98c16be5 2684 NewString = ZeroMem(NewString, NewSize);\r
2247dde4 2685 while (*SourceString != CHAR_NULL) {\r
969c783b 2686 //\r
a405b86d 2687 // if we find the FindTarget and either Skip == FALSE or Skip and we\r
969c783b 2688 // dont have a carrot do a replace...\r
2689 //\r
1e6e84c7 2690 if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0\r
a405b86d 2691 && ((SkipPreCarrot && *(SourceString-1) != L'^') || !SkipPreCarrot)\r
2692 ){\r
975136ab 2693 SourceString += StrLen(FindTarget);\r
0158294b 2694 Size = StrSize(NewString);\r
a405b86d 2695 if ((Size + (StrLen(Replace)*sizeof(CHAR16))) > NewSize) {\r
2696 FreePool(Replace);\r
975136ab 2697 return (EFI_BUFFER_TOO_SMALL);\r
2698 }\r
e75390f0 2699 StrCatS(NewString, NewSize/sizeof(CHAR16), Replace);\r
975136ab 2700 } else {\r
0158294b 2701 Size = StrSize(NewString);\r
2702 if (Size + sizeof(CHAR16) > NewSize) {\r
a405b86d 2703 FreePool(Replace);\r
975136ab 2704 return (EFI_BUFFER_TOO_SMALL);\r
2705 }\r
e75390f0 2706 StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1);\r
975136ab 2707 SourceString++;\r
2708 }\r
2709 }\r
a405b86d 2710 FreePool(Replace);\r
975136ab 2711 return (EFI_SUCCESS);\r
2712}\r
b1f95a06 2713\r
e2f8297f 2714/**\r
2715 Internal worker function to output a string.\r
2716\r
2717 This function will output a string to the correct StdOut.\r
2718\r
2719 @param[in] String The string to print out.\r
2720\r
2721 @retval EFI_SUCCESS The operation was sucessful.\r
2722 @retval !EFI_SUCCESS The operation failed.\r
2723**/\r
2724EFI_STATUS\r
e2f8297f 2725InternalPrintTo (\r
2726 IN CONST CHAR16 *String\r
2727 )\r
2728{\r
2729 UINTN Size;\r
2730 Size = StrSize(String) - sizeof(CHAR16);\r
a405b86d 2731 if (Size == 0) {\r
2732 return (EFI_SUCCESS);\r
2733 }\r
366f81a0 2734 if (gEfiShellParametersProtocol != NULL) {\r
2735 return (gEfiShellProtocol->WriteFile(gEfiShellParametersProtocol->StdOut, &Size, (VOID*)String));\r
e2f8297f 2736 }\r
2737 if (mEfiShellInterface != NULL) {\r
ba0014b9 2738 if (mEfiShellInterface->RedirArgc == 0) {\r
49bd498d 2739 //\r
2740 // Divide in half for old shell. Must be string length not size.\r
ba0014b9 2741 //\r
06c355b4 2742 Size /=2; // Divide in half only when no redirection.\r
2743 }\r
a405b86d 2744 return (mEfiShellInterface->StdOut->Write(mEfiShellInterface->StdOut, &Size, (VOID*)String));\r
e2f8297f 2745 }\r
2746 ASSERT(FALSE);\r
2747 return (EFI_UNSUPPORTED);\r
2748}\r
2749\r
b1f95a06 2750/**\r
2751 Print at a specific location on the screen.\r
2752\r
f1b87e7a 2753 This function will move the cursor to a given screen location and print the specified string\r
1e6e84c7 2754\r
2755 If -1 is specified for either the Row or Col the current screen location for BOTH\r
f1b87e7a 2756 will be used.\r
b1f95a06 2757\r
2758 if either Row or Col is out of range for the current console, then ASSERT\r
2759 if Format is NULL, then ASSERT\r
2760\r
1e6e84c7 2761 In addition to the standard %-based flags as supported by UefiLib Print() this supports\r
b1f95a06 2762 the following additional flags:\r
2763 %N - Set output attribute to normal\r
2764 %H - Set output attribute to highlight\r
2765 %E - Set output attribute to error\r
2766 %B - Set output attribute to blue color\r
2767 %V - Set output attribute to green color\r
2768\r
2769 Note: The background color is controlled by the shell command cls.\r
2770\r
b1f95a06 2771 @param[in] Col the column to print at\r
252d9457 2772 @param[in] Row the row to print at\r
b1f95a06 2773 @param[in] Format the format string\r
2247dde4 2774 @param[in] Marker the marker for the variable argument list\r
b1f95a06 2775\r
a405b86d 2776 @return EFI_SUCCESS The operation was successful.\r
2777 @return EFI_DEVICE_ERROR The console device reported an error.\r
b1f95a06 2778**/\r
a405b86d 2779EFI_STATUS\r
2247dde4 2780InternalShellPrintWorker(\r
b1f95a06 2781 IN INT32 Col OPTIONAL,\r
2782 IN INT32 Row OPTIONAL,\r
2783 IN CONST CHAR16 *Format,\r
252d9457 2784 IN VA_LIST Marker\r
1e6e84c7 2785 )\r
2247dde4 2786{\r
b1f95a06 2787 EFI_STATUS Status;\r
975136ab 2788 CHAR16 *ResumeLocation;\r
2789 CHAR16 *FormatWalker;\r
a405b86d 2790 UINTN OriginalAttribute;\r
89e8537a 2791 CHAR16 *mPostReplaceFormat;\r
2792 CHAR16 *mPostReplaceFormat2;\r
2793\r
2794 mPostReplaceFormat = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));\r
2795 mPostReplaceFormat2 = AllocateZeroPool (PcdGet16 (PcdShellPrintBufferSize));\r
a405b86d 2796\r
f8d3e689 2797 if (mPostReplaceFormat == NULL || mPostReplaceFormat2 == NULL) {\r
2798 SHELL_FREE_NON_NULL(mPostReplaceFormat);\r
2799 SHELL_FREE_NON_NULL(mPostReplaceFormat2);\r
2800 return (EFI_OUT_OF_RESOURCES);\r
2801 }\r
2802\r
a405b86d 2803 Status = EFI_SUCCESS;\r
2804 OriginalAttribute = gST->ConOut->Mode->Attribute;\r
1e6e84c7 2805\r
975136ab 2806 //\r
2807 // Back and forth each time fixing up 1 of our flags...\r
2808 //\r
a405b86d 2809 Status = ShellCopySearchAndReplace(Format, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%N", L"%%N", FALSE, FALSE);\r
975136ab 2810 ASSERT_EFI_ERROR(Status);\r
a405b86d 2811 Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%E", L"%%E", FALSE, FALSE);\r
975136ab 2812 ASSERT_EFI_ERROR(Status);\r
a405b86d 2813 Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%H", L"%%H", FALSE, FALSE);\r
975136ab 2814 ASSERT_EFI_ERROR(Status);\r
a405b86d 2815 Status = ShellCopySearchAndReplace(mPostReplaceFormat, mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), L"%B", L"%%B", FALSE, FALSE);\r
975136ab 2816 ASSERT_EFI_ERROR(Status);\r
a405b86d 2817 Status = ShellCopySearchAndReplace(mPostReplaceFormat2, mPostReplaceFormat, PcdGet16 (PcdShellPrintBufferSize), L"%V", L"%%V", FALSE, FALSE);\r
975136ab 2818 ASSERT_EFI_ERROR(Status);\r
2819\r
2820 //\r
2821 // Use the last buffer from replacing to print from...\r
2822 //\r
a405b86d 2823 UnicodeVSPrint (mPostReplaceFormat2, PcdGet16 (PcdShellPrintBufferSize), mPostReplaceFormat, Marker);\r
b1f95a06 2824\r
2825 if (Col != -1 && Row != -1) {\r
b1f95a06 2826 Status = gST->ConOut->SetCursorPosition(gST->ConOut, Col, Row);\r
975136ab 2827 }\r
2828\r
ecd3d59f 2829 FormatWalker = mPostReplaceFormat2;\r
2247dde4 2830 while (*FormatWalker != CHAR_NULL) {\r
975136ab 2831 //\r
2832 // Find the next attribute change request\r
2833 //\r
2834 ResumeLocation = StrStr(FormatWalker, L"%");\r
2835 if (ResumeLocation != NULL) {\r
2247dde4 2836 *ResumeLocation = CHAR_NULL;\r
975136ab 2837 }\r
2838 //\r
2839 // print the current FormatWalker string\r
2840 //\r
a405b86d 2841 if (StrLen(FormatWalker)>0) {\r
2842 Status = InternalPrintTo(FormatWalker);\r
2843 if (EFI_ERROR(Status)) {\r
2844 break;\r
2845 }\r
2846 }\r
2847\r
975136ab 2848 //\r
2849 // update the attribute\r
2850 //\r
2851 if (ResumeLocation != NULL) {\r
d727614c 2852 if ((ResumeLocation != mPostReplaceFormat2) && (*(ResumeLocation-1) == L'^')) {\r
8bb7441e 2853 //\r
2854 // Move cursor back 1 position to overwrite the ^\r
2855 //\r
2856 gST->ConOut->SetCursorPosition(gST->ConOut, gST->ConOut->Mode->CursorColumn - 1, gST->ConOut->Mode->CursorRow);\r
2857\r
5d46f17b 2858 //\r
2859 // Print a simple '%' symbol\r
2860 //\r
2861 Status = InternalPrintTo(L"%");\r
2862 ResumeLocation = ResumeLocation - 1;\r
2863 } else {\r
2864 switch (*(ResumeLocation+1)) {\r
2865 case (L'N'):\r
2866 gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);\r
a405b86d 2867 break;\r
5d46f17b 2868 case (L'E'):\r
2869 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_YELLOW, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
2870 break;\r
2871 case (L'H'):\r
2872 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_WHITE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
2873 break;\r
2874 case (L'B'):\r
e2ac374f 2875 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTBLUE, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
5d46f17b 2876 break;\r
2877 case (L'V'):\r
e2ac374f 2878 gST->ConOut->SetAttribute(gST->ConOut, EFI_TEXT_ATTR(EFI_LIGHTGREEN, ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)));\r
5d46f17b 2879 break;\r
2880 default:\r
2881 //\r
2882 // Print a simple '%' symbol\r
2883 //\r
2884 Status = InternalPrintTo(L"%");\r
2885 if (EFI_ERROR(Status)) {\r
2886 break;\r
2887 }\r
2888 ResumeLocation = ResumeLocation - 1;\r
2889 break;\r
2890 }\r
975136ab 2891 }\r
2892 } else {\r
2893 //\r
2894 // reset to normal now...\r
2895 //\r
975136ab 2896 break;\r
2897 }\r
2898\r
2899 //\r
2900 // update FormatWalker to Resume + 2 (skip the % and the indicator)\r
2901 //\r
2902 FormatWalker = ResumeLocation + 2;\r
2903 }\r
b1f95a06 2904\r
a405b86d 2905 gST->ConOut->SetAttribute(gST->ConOut, OriginalAttribute);\r
89e8537a 2906\r
2907 SHELL_FREE_NON_NULL(mPostReplaceFormat);\r
2908 SHELL_FREE_NON_NULL(mPostReplaceFormat2);\r
a405b86d 2909 return (Status);\r
5f7431d0 2910}\r
2247dde4 2911\r
2912/**\r
2913 Print at a specific location on the screen.\r
2914\r
e2f8297f 2915 This function will move the cursor to a given screen location and print the specified string.\r
1e6e84c7 2916\r
2917 If -1 is specified for either the Row or Col the current screen location for BOTH\r
2247dde4 2918 will be used.\r
2919\r
e2f8297f 2920 If either Row or Col is out of range for the current console, then ASSERT.\r
2921 If Format is NULL, then ASSERT.\r
2247dde4 2922\r
1e6e84c7 2923 In addition to the standard %-based flags as supported by UefiLib Print() this supports\r
2247dde4 2924 the following additional flags:\r
2925 %N - Set output attribute to normal\r
2926 %H - Set output attribute to highlight\r
2927 %E - Set output attribute to error\r
2928 %B - Set output attribute to blue color\r
2929 %V - Set output attribute to green color\r
2930\r
2931 Note: The background color is controlled by the shell command cls.\r
2932\r
2247dde4 2933 @param[in] Col the column to print at\r
a405b86d 2934 @param[in] Row the row to print at\r
2247dde4 2935 @param[in] Format the format string\r
a405b86d 2936 @param[in] ... The variable argument list.\r
2247dde4 2937\r
a405b86d 2938 @return EFI_SUCCESS The printing was successful.\r
2939 @return EFI_DEVICE_ERROR The console device reported an error.\r
2247dde4 2940**/\r
a405b86d 2941EFI_STATUS\r
2247dde4 2942EFIAPI\r
2943ShellPrintEx(\r
2944 IN INT32 Col OPTIONAL,\r
2945 IN INT32 Row OPTIONAL,\r
2946 IN CONST CHAR16 *Format,\r
2947 ...\r
1e6e84c7 2948 )\r
2247dde4 2949{\r
2950 VA_LIST Marker;\r
a405b86d 2951 EFI_STATUS RetVal;\r
3e082d58 2952 if (Format == NULL) {\r
2953 return (EFI_INVALID_PARAMETER);\r
2954 }\r
2247dde4 2955 VA_START (Marker, Format);\r
a405b86d 2956 RetVal = InternalShellPrintWorker(Col, Row, Format, Marker);\r
e2f8297f 2957 VA_END(Marker);\r
a405b86d 2958 return(RetVal);\r
2247dde4 2959}\r
2960\r
2961/**\r
2962 Print at a specific location on the screen.\r
2963\r
e2f8297f 2964 This function will move the cursor to a given screen location and print the specified string.\r
1e6e84c7 2965\r
2966 If -1 is specified for either the Row or Col the current screen location for BOTH\r
e2f8297f 2967 will be used.\r
2247dde4 2968\r
e2f8297f 2969 If either Row or Col is out of range for the current console, then ASSERT.\r
2970 If Format is NULL, then ASSERT.\r
2247dde4 2971\r
1e6e84c7 2972 In addition to the standard %-based flags as supported by UefiLib Print() this supports\r
2247dde4 2973 the following additional flags:\r
1e6e84c7 2974 %N - Set output attribute to normal.\r
2975 %H - Set output attribute to highlight.\r
2976 %E - Set output attribute to error.\r
2977 %B - Set output attribute to blue color.\r
2978 %V - Set output attribute to green color.\r
2247dde4 2979\r
2980 Note: The background color is controlled by the shell command cls.\r
2981\r
1e6e84c7 2982 @param[in] Col The column to print at.\r
a405b86d 2983 @param[in] Row The row to print at.\r
1e6e84c7 2984 @param[in] Language The language of the string to retrieve. If this parameter\r
2985 is NULL, then the current platform language is used.\r
2986 @param[in] HiiFormatStringId The format string Id for getting from Hii.\r
2987 @param[in] HiiFormatHandle The format string Handle for getting from Hii.\r
a405b86d 2988 @param[in] ... The variable argument list.\r
2247dde4 2989\r
a405b86d 2990 @return EFI_SUCCESS The printing was successful.\r
2991 @return EFI_DEVICE_ERROR The console device reported an error.\r
2247dde4 2992**/\r
a405b86d 2993EFI_STATUS\r
2247dde4 2994EFIAPI\r
2995ShellPrintHiiEx(\r
2996 IN INT32 Col OPTIONAL,\r
2997 IN INT32 Row OPTIONAL,\r
1e6e84c7 2998 IN CONST CHAR8 *Language OPTIONAL,\r
2247dde4 2999 IN CONST EFI_STRING_ID HiiFormatStringId,\r
3000 IN CONST EFI_HANDLE HiiFormatHandle,\r
3001 ...\r
3002 )\r
3003{\r
3004 VA_LIST Marker;\r
3005 CHAR16 *HiiFormatString;\r
a405b86d 3006 EFI_STATUS RetVal;\r
2247dde4 3007\r
eeb9744e
RN
3008 RetVal = EFI_DEVICE_ERROR;\r
3009\r
2247dde4 3010 VA_START (Marker, HiiFormatHandle);\r
1e6e84c7 3011 HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, Language);\r
eeb9744e
RN
3012 if (HiiFormatString != NULL) {\r
3013 RetVal = InternalShellPrintWorker (Col, Row, HiiFormatString, Marker);\r
3014 SHELL_FREE_NON_NULL (HiiFormatString);\r
3015 }\r
e2f8297f 3016 VA_END(Marker);\r
2247dde4 3017\r
3018 return (RetVal);\r
3019}\r
3020\r
3021/**\r
3022 Function to determine if a given filename represents a file or a directory.\r
3023\r
3024 @param[in] DirName Path to directory to test.\r
3025\r
c8c22591 3026 @retval EFI_SUCCESS The Path represents a directory\r
3027 @retval EFI_NOT_FOUND The Path does not represent a directory\r
3028 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
3029 @return The path failed to open\r
2247dde4 3030**/\r
3031EFI_STATUS\r
3032EFIAPI\r
3033ShellIsDirectory(\r
3034 IN CONST CHAR16 *DirName\r
3035 )\r
3036{\r
3037 EFI_STATUS Status;\r
a405b86d 3038 SHELL_FILE_HANDLE Handle;\r
3e082d58 3039 CHAR16 *TempLocation;\r
3040 CHAR16 *TempLocation2;\r
2247dde4 3041\r
ecd3d59f 3042 ASSERT(DirName != NULL);\r
3043\r
a405b86d 3044 Handle = NULL;\r
3045 TempLocation = NULL;\r
2247dde4 3046\r
3047 Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);\r
3048 if (EFI_ERROR(Status)) {\r
a405b86d 3049 //\r
3050 // try good logic first.\r
3051 //\r
366f81a0 3052 if (gEfiShellProtocol != NULL) {\r
3e082d58 3053 TempLocation = StrnCatGrow(&TempLocation, NULL, DirName, 0);\r
c8c22591 3054 if (TempLocation == NULL) {\r
3055 ShellCloseFile(&Handle);\r
3056 return (EFI_OUT_OF_RESOURCES);\r
3057 }\r
3e082d58 3058 TempLocation2 = StrStr(TempLocation, L":");\r
3059 if (TempLocation2 != NULL && StrLen(StrStr(TempLocation, L":")) == 2) {\r
3060 *(TempLocation2+1) = CHAR_NULL;\r
a405b86d 3061 }\r
366f81a0 3062 if (gEfiShellProtocol->GetDevicePathFromMap(TempLocation) != NULL) {\r
a405b86d 3063 FreePool(TempLocation);\r
3064 return (EFI_SUCCESS);\r
3065 }\r
3066 FreePool(TempLocation);\r
3067 } else {\r
3068 //\r
3069 // probably a map name?!?!!?\r
3070 //\r
3071 TempLocation = StrStr(DirName, L"\\");\r
3072 if (TempLocation != NULL && *(TempLocation+1) == CHAR_NULL) {\r
3073 return (EFI_SUCCESS);\r
3074 }\r
3075 }\r
2247dde4 3076 return (Status);\r
3077 }\r
3078\r
3079 if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {\r
3080 ShellCloseFile(&Handle);\r
3081 return (EFI_SUCCESS);\r
3082 }\r
3083 ShellCloseFile(&Handle);\r
3084 return (EFI_NOT_FOUND);\r
3085}\r
3086\r
36a9d672 3087/**\r
3088 Function to determine if a given filename represents a file.\r
3089\r
3090 @param[in] Name Path to file to test.\r
3091\r
3092 @retval EFI_SUCCESS The Path represents a file.\r
3093 @retval EFI_NOT_FOUND The Path does not represent a file.\r
3094 @retval other The path failed to open.\r
3095**/\r
3096EFI_STATUS\r
3097EFIAPI\r
3098ShellIsFile(\r
3099 IN CONST CHAR16 *Name\r
3100 )\r
3101{\r
3102 EFI_STATUS Status;\r
a405b86d 3103 SHELL_FILE_HANDLE Handle;\r
36a9d672 3104\r
ecd3d59f 3105 ASSERT(Name != NULL);\r
3106\r
36a9d672 3107 Handle = NULL;\r
3108\r
3109 Status = ShellOpenFileByName(Name, &Handle, EFI_FILE_MODE_READ, 0);\r
3110 if (EFI_ERROR(Status)) {\r
3111 return (Status);\r
3112 }\r
3113\r
3114 if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
3115 ShellCloseFile(&Handle);\r
3116 return (EFI_SUCCESS);\r
3117 }\r
3118 ShellCloseFile(&Handle);\r
3119 return (EFI_NOT_FOUND);\r
3120}\r
3121\r
b3011f40 3122/**\r
3123 Function to determine if a given filename represents a file.\r
3124\r
3125 This will search the CWD and then the Path.\r
3126\r
3127 If Name is NULL, then ASSERT.\r
3128\r
3129 @param[in] Name Path to file to test.\r
3130\r
3131 @retval EFI_SUCCESS The Path represents a file.\r
3132 @retval EFI_NOT_FOUND The Path does not represent a file.\r
3133 @retval other The path failed to open.\r
3134**/\r
3135EFI_STATUS\r
3136EFIAPI\r
3137ShellIsFileInPath(\r
3138 IN CONST CHAR16 *Name\r
a405b86d 3139 )\r
3140{\r
b3011f40 3141 CHAR16 *NewName;\r
3142 EFI_STATUS Status;\r
3143\r
3144 if (!EFI_ERROR(ShellIsFile(Name))) {\r
a405b86d 3145 return (EFI_SUCCESS);\r
b3011f40 3146 }\r
3147\r
3148 NewName = ShellFindFilePath(Name);\r
3149 if (NewName == NULL) {\r
3150 return (EFI_NOT_FOUND);\r
3151 }\r
3152 Status = ShellIsFile(NewName);\r
3153 FreePool(NewName);\r
3154 return (Status);\r
3155}\r
252d9457 3156\r
74b0fb8c
JC
3157/**\r
3158 Function return the number converted from a hex representation of a number.\r
3159\r
3160 Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid\r
3161 result. Use ShellConvertStringToUint64 instead.\r
3162\r
3163 @param[in] String String representation of a number.\r
3164\r
3165 @return The unsigned integer result of the conversion.\r
3166 @retval (UINTN)(-1) An error occured.\r
3167**/\r
3168UINTN\r
3169EFIAPI\r
3170ShellHexStrToUintn(\r
3171 IN CONST CHAR16 *String\r
3172 )\r
3173{\r
3174 UINT64 RetVal;\r
3175\r
3176 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {\r
3177 return ((UINTN)RetVal);\r
3178 }\r
ba0014b9 3179\r
74b0fb8c
JC
3180 return ((UINTN)(-1));\r
3181}\r
3182\r
125c2cf4 3183/**\r
1e6e84c7 3184 Function to determine whether a string is decimal or hex representation of a number\r
d59fc244 3185 and return the number converted from the string. Spaces are always skipped.\r
125c2cf4 3186\r
3187 @param[in] String String representation of a number\r
3188\r
252d9457 3189 @return the number\r
3190 @retval (UINTN)(-1) An error ocurred.\r
125c2cf4 3191**/\r
3192UINTN\r
3193EFIAPI\r
3194ShellStrToUintn(\r
3195 IN CONST CHAR16 *String\r
3196 )\r
3197{\r
252d9457 3198 UINT64 RetVal;\r
3199 BOOLEAN Hex;\r
3200\r
3201 Hex = FALSE;\r
3202\r
658bf43e 3203 if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) {\r
252d9457 3204 Hex = TRUE;\r
125c2cf4 3205 }\r
252d9457 3206\r
3207 if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, Hex, TRUE))) {\r
3208 return ((UINTN)RetVal);\r
3209 }\r
3210 return ((UINTN)(-1));\r
125c2cf4 3211}\r
3212\r
3213/**\r
3214 Safely append with automatic string resizing given length of Destination and\r
3215 desired length of copy from Source.\r
3216\r
3217 append the first D characters of Source to the end of Destination, where D is\r
3218 the lesser of Count and the StrLen() of Source. If appending those D characters\r
3219 will fit within Destination (whose Size is given as CurrentSize) and\r
1e6e84c7 3220 still leave room for a NULL terminator, then those characters are appended,\r
3221 starting at the original terminating NULL of Destination, and a new terminating\r
3222 NULL is appended.\r
125c2cf4 3223\r
3224 If appending D characters onto Destination will result in a overflow of the size\r
3225 given in CurrentSize the string will be grown such that the copy can be performed\r
3226 and CurrentSize will be updated to the new size.\r
3227\r
3228 If Source is NULL, there is nothing to append, just return the current buffer in\r
3229 Destination.\r
3230\r
3231 if Destination is NULL, then ASSERT()\r
3232 if Destination's current length (including NULL terminator) is already more then\r
3233 CurrentSize, then ASSERT()\r
3234\r
4ff7e37b
ED
3235 @param[in, out] Destination The String to append onto\r
3236 @param[in, out] CurrentSize on call the number of bytes in Destination. On\r
125c2cf4 3237 return possibly the new size (still in bytes). if NULL\r
3238 then allocate whatever is needed.\r
3239 @param[in] Source The String to append from\r
3240 @param[in] Count Maximum number of characters to append. if 0 then\r
3241 all are appended.\r
3242\r
3243 @return Destination return the resultant string.\r
3244**/\r
3245CHAR16*\r
3246EFIAPI\r
3247StrnCatGrow (\r
3248 IN OUT CHAR16 **Destination,\r
3249 IN OUT UINTN *CurrentSize,\r
3250 IN CONST CHAR16 *Source,\r
3251 IN UINTN Count\r
3252 )\r
3253{\r
3254 UINTN DestinationStartSize;\r
3255 UINTN NewSize;\r
3256\r
3257 //\r
3258 // ASSERTs\r
3259 //\r
3260 ASSERT(Destination != NULL);\r
3261\r
3262 //\r
3263 // If there's nothing to do then just return Destination\r
3264 //\r
3265 if (Source == NULL) {\r
3266 return (*Destination);\r
3267 }\r
3268\r
3269 //\r
3270 // allow for un-initialized pointers, based on size being 0\r
3271 //\r
3272 if (CurrentSize != NULL && *CurrentSize == 0) {\r
3273 *Destination = NULL;\r
3274 }\r
3275\r
3276 //\r
3277 // allow for NULL pointers address as Destination\r
3278 //\r
3279 if (*Destination != NULL) {\r
3280 ASSERT(CurrentSize != 0);\r
3281 DestinationStartSize = StrSize(*Destination);\r
3282 ASSERT(DestinationStartSize <= *CurrentSize);\r
3283 } else {\r
3284 DestinationStartSize = 0;\r
3285// ASSERT(*CurrentSize == 0);\r
3286 }\r
3287\r
3288 //\r
3289 // Append all of Source?\r
3290 //\r
3291 if (Count == 0) {\r
3292 Count = StrLen(Source);\r
3293 }\r
3294\r
3295 //\r
3296 // Test and grow if required\r
3297 //\r
3298 if (CurrentSize != NULL) {\r
3299 NewSize = *CurrentSize;\r
f480fdc0
ED
3300 if (NewSize < DestinationStartSize + (Count * sizeof(CHAR16))) {\r
3301 while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {\r
3302 NewSize += 2 * Count * sizeof(CHAR16);\r
3303 }\r
3304 *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
3305 *CurrentSize = NewSize;\r
125c2cf4 3306 }\r
125c2cf4 3307 } else {\r
c587fd3e
QS
3308 NewSize = (Count+1)*sizeof(CHAR16);\r
3309 *Destination = AllocateZeroPool(NewSize);\r
125c2cf4 3310 }\r
3311\r
3312 //\r
3313 // Now use standard StrnCat on a big enough buffer\r
3314 //\r
c9d92df0 3315 if (*Destination == NULL) {\r
3316 return (NULL);\r
3317 }\r
ba0014b9 3318\r
c587fd3e 3319 StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);\r
e75390f0 3320 return *Destination;\r
125c2cf4 3321}\r
c9d92df0 3322\r
3323/**\r
3324 Prompt the user and return the resultant answer to the requestor.\r
3325\r
3326 This function will display the requested question on the shell prompt and then\r
1d322461 3327 wait for an appropriate answer to be input from the console.\r
c9d92df0 3328\r
a405b86d 3329 if the SHELL_PROMPT_REQUEST_TYPE is SHELL_PROMPT_REQUEST_TYPE_YESNO, ShellPromptResponseTypeQuitContinue\r
c9d92df0 3330 or SHELL_PROMPT_REQUEST_TYPE_YESNOCANCEL then *Response is of type SHELL_PROMPT_RESPONSE.\r
3331\r
a405b86d 3332 if the SHELL_PROMPT_REQUEST_TYPE is ShellPromptResponseTypeFreeform then *Response is of type\r
c9d92df0 3333 CHAR16*.\r
3334\r
3335 In either case *Response must be callee freed if Response was not NULL;\r
3336\r
3337 @param Type What type of question is asked. This is used to filter the input\r
3338 to prevent invalid answers to question.\r
3339 @param Prompt Pointer to string prompt to use to request input.\r
3340 @param Response Pointer to Response which will be populated upon return.\r
3341\r
3342 @retval EFI_SUCCESS The operation was sucessful.\r
3343 @retval EFI_UNSUPPORTED The operation is not supported as requested.\r
3344 @retval EFI_INVALID_PARAMETER A parameter was invalid.\r
3345 @return other The operation failed.\r
3346**/\r
3347EFI_STATUS\r
3348EFIAPI\r
3349ShellPromptForResponse (\r
3350 IN SHELL_PROMPT_REQUEST_TYPE Type,\r
3351 IN CHAR16 *Prompt OPTIONAL,\r
3352 IN OUT VOID **Response OPTIONAL\r
3353 )\r
3354{\r
3355 EFI_STATUS Status;\r
3356 EFI_INPUT_KEY Key;\r
3357 UINTN EventIndex;\r
3358 SHELL_PROMPT_RESPONSE *Resp;\r
a405b86d 3359 UINTN Size;\r
3360 CHAR16 *Buffer;\r
c9d92df0 3361\r
a405b86d 3362 Status = EFI_UNSUPPORTED;\r
3363 Resp = NULL;\r
3364 Buffer = NULL;\r
3365 Size = 0;\r
3366 if (Type != ShellPromptResponseTypeFreeform) {\r
252d9457 3367 Resp = (SHELL_PROMPT_RESPONSE*)AllocateZeroPool(sizeof(SHELL_PROMPT_RESPONSE));\r
3e082d58 3368 if (Resp == NULL) {\r
3369 return (EFI_OUT_OF_RESOURCES);\r
3370 }\r
90bfa227 3371 }\r
c9d92df0 3372\r
3373 switch(Type) {\r
a405b86d 3374 case ShellPromptResponseTypeQuitContinue:\r
c9d92df0 3375 if (Prompt != NULL) {\r
3376 ShellPrintEx(-1, -1, L"%s", Prompt);\r
3377 }\r
3378 //\r
3379 // wait for valid response\r
3380 //\r
3381 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
3382 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
31b018a6
JC
3383 if (EFI_ERROR(Status)) {\r
3384 break;\r
3385 }\r
c9d92df0 3386 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
3387 if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') {\r
a405b86d 3388 *Resp = ShellPromptResponseQuit;\r
c9d92df0 3389 } else {\r
a405b86d 3390 *Resp = ShellPromptResponseContinue;\r
c9d92df0 3391 }\r
3392 break;\r
a405b86d 3393 case ShellPromptResponseTypeYesNoCancel:\r
c9d92df0 3394 if (Prompt != NULL) {\r
3395 ShellPrintEx(-1, -1, L"%s", Prompt);\r
3396 }\r
3397 //\r
3398 // wait for valid response\r
3399 //\r
a405b86d 3400 *Resp = ShellPromptResponseMax;\r
3401 while (*Resp == ShellPromptResponseMax) {\r
194ae48d
JC
3402 if (ShellGetExecutionBreakFlag()) {\r
3403 Status = EFI_ABORTED;\r
3404 break;\r
3405 }\r
c9d92df0 3406 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
3407 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
31b018a6
JC
3408 if (EFI_ERROR(Status)) {\r
3409 break;\r
3410 }\r
c9d92df0 3411 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
3412 switch (Key.UnicodeChar) {\r
3413 case L'Y':\r
3414 case L'y':\r
a405b86d 3415 *Resp = ShellPromptResponseYes;\r
c9d92df0 3416 break;\r
3417 case L'N':\r
3418 case L'n':\r
a405b86d 3419 *Resp = ShellPromptResponseNo;\r
3420 break;\r
3421 case L'C':\r
3422 case L'c':\r
3423 *Resp = ShellPromptResponseCancel;\r
3424 break;\r
3425 }\r
3426 }\r
ac55b925
TS
3427 break;\r
3428 case ShellPromptResponseTypeYesNoAllCancel:\r
a405b86d 3429 if (Prompt != NULL) {\r
3430 ShellPrintEx(-1, -1, L"%s", Prompt);\r
3431 }\r
3432 //\r
3433 // wait for valid response\r
3434 //\r
3435 *Resp = ShellPromptResponseMax;\r
3436 while (*Resp == ShellPromptResponseMax) {\r
194ae48d
JC
3437 if (ShellGetExecutionBreakFlag()) {\r
3438 Status = EFI_ABORTED;\r
3439 break;\r
3440 }\r
a405b86d 3441 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
3442 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
31b018a6
JC
3443 if (EFI_ERROR(Status)) {\r
3444 break;\r
3445 }\r
ac55b925
TS
3446\r
3447 if (Key.UnicodeChar <= 127 && Key.UnicodeChar >= 32) {\r
3448 ShellPrintEx (-1, -1, L"%c", Key.UnicodeChar);\r
3449 }\r
3450\r
a405b86d 3451 switch (Key.UnicodeChar) {\r
3452 case L'Y':\r
3453 case L'y':\r
3454 *Resp = ShellPromptResponseYes;\r
3455 break;\r
3456 case L'N':\r
3457 case L'n':\r
3458 *Resp = ShellPromptResponseNo;\r
c9d92df0 3459 break;\r
3460 case L'A':\r
3461 case L'a':\r
a405b86d 3462 *Resp = ShellPromptResponseAll;\r
c9d92df0 3463 break;\r
3464 case L'C':\r
3465 case L'c':\r
a405b86d 3466 *Resp = ShellPromptResponseCancel;\r
c9d92df0 3467 break;\r
3468 }\r
3469 }\r
3470 break;\r
a405b86d 3471 case ShellPromptResponseTypeEnterContinue:\r
3472 case ShellPromptResponseTypeAnyKeyContinue:\r
c9d92df0 3473 if (Prompt != NULL) {\r
3474 ShellPrintEx(-1, -1, L"%s", Prompt);\r
3475 }\r
3476 //\r
3477 // wait for valid response\r
3478 //\r
a405b86d 3479 *Resp = ShellPromptResponseMax;\r
3480 while (*Resp == ShellPromptResponseMax) {\r
194ae48d
JC
3481 if (ShellGetExecutionBreakFlag()) {\r
3482 Status = EFI_ABORTED;\r
3483 break;\r
3484 }\r
c9d92df0 3485 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
a405b86d 3486 if (Type == ShellPromptResponseTypeEnterContinue) {\r
c9d92df0 3487 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
31b018a6
JC
3488 if (EFI_ERROR(Status)) {\r
3489 break;\r
3490 }\r
c9d92df0 3491 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
3492 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
a405b86d 3493 *Resp = ShellPromptResponseContinue;\r
c9d92df0 3494 break;\r
3495 }\r
3496 }\r
a405b86d 3497 if (Type == ShellPromptResponseTypeAnyKeyContinue) {\r
3498 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
3499 ASSERT_EFI_ERROR(Status);\r
3500 *Resp = ShellPromptResponseContinue;\r
3501 break;\r
3502 }\r
3503 }\r
3504 break;\r
3505 case ShellPromptResponseTypeYesNo:\r
3506 if (Prompt != NULL) {\r
3507 ShellPrintEx(-1, -1, L"%s", Prompt);\r
3508 }\r
3509 //\r
3510 // wait for valid response\r
3511 //\r
3512 *Resp = ShellPromptResponseMax;\r
3513 while (*Resp == ShellPromptResponseMax) {\r
194ae48d
JC
3514 if (ShellGetExecutionBreakFlag()) {\r
3515 Status = EFI_ABORTED;\r
3516 break;\r
3517 }\r
a405b86d 3518 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
3519 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
31b018a6
JC
3520 if (EFI_ERROR(Status)) {\r
3521 break;\r
3522 }\r
a405b86d 3523 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
3524 switch (Key.UnicodeChar) {\r
3525 case L'Y':\r
3526 case L'y':\r
3527 *Resp = ShellPromptResponseYes;\r
3528 break;\r
3529 case L'N':\r
3530 case L'n':\r
3531 *Resp = ShellPromptResponseNo;\r
3532 break;\r
3533 }\r
3534 }\r
3535 break;\r
3536 case ShellPromptResponseTypeFreeform:\r
3537 if (Prompt != NULL) {\r
3538 ShellPrintEx(-1, -1, L"%s", Prompt);\r
3539 }\r
3540 while(1) {\r
194ae48d
JC
3541 if (ShellGetExecutionBreakFlag()) {\r
3542 Status = EFI_ABORTED;\r
3543 break;\r
3544 }\r
a405b86d 3545 gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
3546 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
31b018a6
JC
3547 if (EFI_ERROR(Status)) {\r
3548 break;\r
3549 }\r
a405b86d 3550 ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
3551 if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
c9d92df0 3552 break;\r
3553 }\r
a405b86d 3554 ASSERT((Buffer == NULL && Size == 0) || (Buffer != NULL));\r
3555 StrnCatGrow(&Buffer, &Size, &Key.UnicodeChar, 1);\r
c9d92df0 3556 }\r
3557 break;\r
a405b86d 3558 //\r
3559 // This is the location to add new prompt types.\r
194ae48d 3560 // If your new type loops remember to add ExecutionBreak support.\r
a405b86d 3561 //\r
c9d92df0 3562 default:\r
a405b86d 3563 ASSERT(FALSE);\r
c9d92df0 3564 }\r
3565\r
3566 if (Response != NULL) {\r
a405b86d 3567 if (Resp != NULL) {\r
3568 *Response = Resp;\r
3569 } else if (Buffer != NULL) {\r
3570 *Response = Buffer;\r
3571 }\r
c9d92df0 3572 } else {\r
a405b86d 3573 if (Resp != NULL) {\r
3574 FreePool(Resp);\r
3575 }\r
3576 if (Buffer != NULL) {\r
3577 FreePool(Buffer);\r
3578 }\r
c9d92df0 3579 }\r
3580\r
a405b86d 3581 ShellPrintEx(-1, -1, L"\r\n");\r
c9d92df0 3582 return (Status);\r
3583}\r
3584\r
3585/**\r
3586 Prompt the user and return the resultant answer to the requestor.\r
3587\r
3588 This function is the same as ShellPromptForResponse, except that the prompt is\r
3589 automatically pulled from HII.\r
3590\r
3591 @param Type What type of question is asked. This is used to filter the input\r
3592 to prevent invalid answers to question.\r
a405b86d 3593 @param[in] HiiFormatStringId The format string Id for getting from Hii.\r
3594 @param[in] HiiFormatHandle The format string Handle for getting from Hii.\r
3595 @param Response Pointer to Response which will be populated upon return.\r
c9d92df0 3596\r
3597 @retval EFI_SUCCESS the operation was sucessful.\r
3598 @return other the operation failed.\r
3599\r
3600 @sa ShellPromptForResponse\r
3601**/\r
3602EFI_STATUS\r
3603EFIAPI\r
3604ShellPromptForResponseHii (\r
3605 IN SHELL_PROMPT_REQUEST_TYPE Type,\r
3606 IN CONST EFI_STRING_ID HiiFormatStringId,\r
3607 IN CONST EFI_HANDLE HiiFormatHandle,\r
3608 IN OUT VOID **Response\r
3609 )\r
3610{\r
3611 CHAR16 *Prompt;\r
3612 EFI_STATUS Status;\r
3613\r
3614 Prompt = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL);\r
3615 Status = ShellPromptForResponse(Type, Prompt, Response);\r
3616 FreePool(Prompt);\r
3617 return (Status);\r
3618}\r
3619\r
a405b86d 3620/**\r
3621 Function to determin if an entire string is a valid number.\r
3622\r
3623 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.\r
c9d92df0 3624\r
a405b86d 3625 @param[in] String The string to evaluate.\r
3626 @param[in] ForceHex TRUE - always assume hex.\r
3627 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.\r
658bf43e 3628 @param[in] TimeNumbers TRUE to allow numbers with ":", FALSE otherwise.\r
a405b86d 3629\r
3630 @retval TRUE It is all numeric (dec/hex) characters.\r
3631 @retval FALSE There is a non-numeric character.\r
3632**/\r
3633BOOLEAN\r
252d9457 3634InternalShellIsHexOrDecimalNumber (\r
a405b86d 3635 IN CONST CHAR16 *String,\r
3636 IN CONST BOOLEAN ForceHex,\r
658bf43e 3637 IN CONST BOOLEAN StopAtSpace,\r
3638 IN CONST BOOLEAN TimeNumbers\r
a405b86d 3639 )\r
3640{\r
3641 BOOLEAN Hex;\r
ee33344c
RN
3642 BOOLEAN LeadingZero;\r
3643\r
3644 if (String == NULL) {\r
3645 return FALSE;\r
3646 }\r
a405b86d 3647\r
3648 //\r
3649 // chop off a single negative sign\r
3650 //\r
ee33344c 3651 if (*String == L'-') {\r
a405b86d 3652 String++;\r
3653 }\r
b0934ac4 3654\r
ee33344c
RN
3655 if (*String == CHAR_NULL) {\r
3656 return FALSE;\r
a405b86d 3657 }\r
3658\r
3659 //\r
3660 // chop leading zeroes\r
3661 //\r
ee33344c
RN
3662 LeadingZero = FALSE;\r
3663 while(*String == L'0'){\r
a405b86d 3664 String++;\r
ee33344c 3665 LeadingZero = TRUE;\r
a405b86d 3666 }\r
3667 //\r
3668 // allow '0x' or '0X', but not 'x' or 'X'\r
3669 //\r
ee33344c
RN
3670 if (*String == L'x' || *String == L'X') {\r
3671 if (!LeadingZero) {\r
a405b86d 3672 //\r
3673 // we got an x without a preceeding 0\r
3674 //\r
3675 return (FALSE);\r
3676 }\r
3677 String++;\r
3678 Hex = TRUE;\r
3679 } else if (ForceHex) {\r
3680 Hex = TRUE;\r
3681 } else {\r
3682 Hex = FALSE;\r
3683 }\r
3684\r
3685 //\r
3686 // loop through the remaining characters and use the lib function\r
3687 //\r
ee33344c 3688 for ( ; *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){\r
658bf43e 3689 if (TimeNumbers && (String[0] == L':')) {\r
3690 continue;\r
3691 }\r
a405b86d 3692 if (Hex) {\r
3693 if (!ShellIsHexaDecimalDigitCharacter(*String)) {\r
3694 return (FALSE);\r
3695 }\r
3696 } else {\r
3697 if (!ShellIsDecimalDigitCharacter(*String)) {\r
3698 return (FALSE);\r
3699 }\r
3700 }\r
3701 }\r
252d9457 3702\r
a405b86d 3703 return (TRUE);\r
3704}\r
3705\r
3706/**\r
3707 Function to determine if a given filename exists.\r
3708\r
3709 @param[in] Name Path to test.\r
3710\r
3711 @retval EFI_SUCCESS The Path represents a file.\r
3712 @retval EFI_NOT_FOUND The Path does not represent a file.\r
3713 @retval other The path failed to open.\r
3714**/\r
3715EFI_STATUS\r
3716EFIAPI\r
3717ShellFileExists(\r
3718 IN CONST CHAR16 *Name\r
3719 )\r
3720{\r
3721 EFI_STATUS Status;\r
3722 EFI_SHELL_FILE_INFO *List;\r
3723\r
3724 ASSERT(Name != NULL);\r
3725\r
3726 List = NULL;\r
3727 Status = ShellOpenFileMetaArg((CHAR16*)Name, EFI_FILE_MODE_READ, &List);\r
3728 if (EFI_ERROR(Status)) {\r
3729 return (Status);\r
3730 }\r
3731\r
3732 ShellCloseFileMetaArg(&List);\r
3733\r
3734 return (EFI_SUCCESS);\r
3735}\r
252d9457 3736\r
252d9457 3737/**\r
3738 Convert a Unicode character to numerical value.\r
3739\r
3740 This internal function only deal with Unicode character\r
3741 which maps to a valid hexadecimal ASII character, i.e.\r
b0934ac4 3742 L'0' to L'9', L'a' to L'f' or L'A' to L'F'. For other\r
252d9457 3743 Unicode character, the value returned does not make sense.\r
3744\r
3745 @param Char The character to convert.\r
3746\r
3747 @return The numerical value converted.\r
3748\r
3749**/\r
3750UINTN\r
252d9457 3751InternalShellHexCharToUintn (\r
3752 IN CHAR16 Char\r
3753 )\r
3754{\r
3755 if (ShellIsDecimalDigitCharacter (Char)) {\r
3756 return Char - L'0';\r
3757 }\r
3758\r
3d086fed 3759 return (10 + CharToUpper (Char) - L'A');\r
252d9457 3760}\r
3761\r
3762/**\r
3763 Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.\r
3764\r
80f3e34f 3765 This function returns a value of type UINT64 by interpreting the contents\r
252d9457 3766 of the Unicode string specified by String as a hexadecimal number.\r
3767 The format of the input Unicode string String is:\r
3768\r
3769 [spaces][zeros][x][hexadecimal digits].\r
3770\r
3771 The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].\r
3772 The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.\r
3773 If "x" appears in the input string, it must be prefixed with at least one 0.\r
3774 The function will ignore the pad space, which includes spaces or tab characters,\r
3775 before [zeros], [x] or [hexadecimal digit]. The running zero before [x] or\r
3776 [hexadecimal digit] will be ignored. Then, the decoding starts after [x] or the\r
3777 first valid hexadecimal digit. Then, the function stops at the first character that is\r
3778 a not a valid hexadecimal character or NULL, whichever one comes first.\r
3779\r
3780 If String has only pad spaces, then zero is returned.\r
3781 If String has no leading pad spaces, leading zeros or valid hexadecimal digits,\r
3782 then zero is returned.\r
3783\r
3784 @param[in] String A pointer to a Null-terminated Unicode string.\r
3785 @param[out] Value Upon a successful return the value of the conversion.\r
3786 @param[in] StopAtSpace FALSE to skip spaces.\r
3787\r
3788 @retval EFI_SUCCESS The conversion was successful.\r
3789 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.\r
3790 @retval EFI_DEVICE_ERROR An overflow occured.\r
3791**/\r
3792EFI_STATUS\r
252d9457 3793InternalShellStrHexToUint64 (\r
3794 IN CONST CHAR16 *String,\r
3795 OUT UINT64 *Value,\r
3796 IN CONST BOOLEAN StopAtSpace\r
3797 )\r
3798{\r
3799 UINT64 Result;\r
3800\r
3801 if (String == NULL || StrSize(String) == 0 || Value == NULL) {\r
3802 return (EFI_INVALID_PARAMETER);\r
3803 }\r
b0934ac4 3804\r
252d9457 3805 //\r
b0934ac4 3806 // Ignore the pad spaces (space or tab)\r
252d9457 3807 //\r
3808 while ((*String == L' ') || (*String == L'\t')) {\r
3809 String++;\r
3810 }\r
3811\r
3812 //\r
3813 // Ignore leading Zeros after the spaces\r
3814 //\r
3815 while (*String == L'0') {\r
3816 String++;\r
3817 }\r
3818\r
3d086fed 3819 if (CharToUpper (*String) == L'X') {\r
252d9457 3820 if (*(String - 1) != L'0') {\r
3821 return 0;\r
3822 }\r
3823 //\r
3824 // Skip the 'X'\r
3825 //\r
3826 String++;\r
3827 }\r
3828\r
3829 Result = 0;\r
b0934ac4 3830\r
252d9457 3831 //\r
80f3e34f 3832 // there is a space where there should't be\r
252d9457 3833 //\r
80f3e34f
JC
3834 if (*String == L' ') {\r
3835 return (EFI_INVALID_PARAMETER);\r
252d9457 3836 }\r
b0934ac4 3837\r
252d9457 3838 while (ShellIsHexaDecimalDigitCharacter (*String)) {\r
3839 //\r
b0934ac4 3840 // If the Hex Number represented by String overflows according\r
80f3e34f 3841 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.\r
252d9457 3842 //\r
3843 if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {\r
3844// if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {\r
3845 return (EFI_DEVICE_ERROR);\r
3846 }\r
3847\r
3848 Result = (LShiftU64(Result, 4));\r
3849 Result += InternalShellHexCharToUintn (*String);\r
3850 String++;\r
3851\r
3852 //\r
49bd498d 3853 // stop at spaces if requested\r
252d9457 3854 //\r
49bd498d 3855 if (StopAtSpace && *String == L' ') {\r
3856 break;\r
252d9457 3857 }\r
3858 }\r
3859\r
3860 *Value = Result;\r
3861 return (EFI_SUCCESS);\r
3862}\r
3863\r
3864/**\r
3865 Convert a Null-terminated Unicode decimal string to a value of\r
3866 type UINT64.\r
3867\r
3868 This function returns a value of type UINT64 by interpreting the contents\r
3869 of the Unicode string specified by String as a decimal number. The format\r
3870 of the input Unicode string String is:\r
3871\r
3872 [spaces] [decimal digits].\r
3873\r
3874 The valid decimal digit character is in the range [0-9]. The\r
3875 function will ignore the pad space, which includes spaces or\r
3876 tab characters, before [decimal digits]. The running zero in the\r
3877 beginning of [decimal digits] will be ignored. Then, the function\r
3878 stops at the first character that is a not a valid decimal character\r
3879 or a Null-terminator, whichever one comes first.\r
3880\r
3881 If String has only pad spaces, then 0 is returned.\r
3882 If String has no pad spaces or valid decimal digits,\r
3883 then 0 is returned.\r
3884\r
3885 @param[in] String A pointer to a Null-terminated Unicode string.\r
3886 @param[out] Value Upon a successful return the value of the conversion.\r
3887 @param[in] StopAtSpace FALSE to skip spaces.\r
3888\r
3889 @retval EFI_SUCCESS The conversion was successful.\r
3890 @retval EFI_INVALID_PARAMETER A parameter was NULL or invalid.\r
3891 @retval EFI_DEVICE_ERROR An overflow occured.\r
3892**/\r
3893EFI_STATUS\r
252d9457 3894InternalShellStrDecimalToUint64 (\r
3895 IN CONST CHAR16 *String,\r
3896 OUT UINT64 *Value,\r
3897 IN CONST BOOLEAN StopAtSpace\r
3898 )\r
3899{\r
3900 UINT64 Result;\r
3901\r
3902 if (String == NULL || StrSize (String) == 0 || Value == NULL) {\r
3903 return (EFI_INVALID_PARAMETER);\r
3904 }\r
3905\r
3906 //\r
3907 // Ignore the pad spaces (space or tab)\r
3908 //\r
3909 while ((*String == L' ') || (*String == L'\t')) {\r
3910 String++;\r
3911 }\r
3912\r
3913 //\r
3914 // Ignore leading Zeros after the spaces\r
3915 //\r
3916 while (*String == L'0') {\r
3917 String++;\r
3918 }\r
3919\r
3920 Result = 0;\r
3921\r
3922 //\r
ba0014b9 3923 // Stop upon space if requested\r
80f3e34f 3924 // (if the whole value was 0)\r
252d9457 3925 //\r
80f3e34f
JC
3926 if (StopAtSpace && *String == L' ') {\r
3927 *Value = Result;\r
3928 return (EFI_SUCCESS);\r
252d9457 3929 }\r
80f3e34f 3930\r
252d9457 3931 while (ShellIsDecimalDigitCharacter (*String)) {\r
3932 //\r
b0934ac4 3933 // If the number represented by String overflows according\r
80f3e34f 3934 // to the range defined by UINT64, then return EFI_DEVICE_ERROR.\r
252d9457 3935 //\r
b0934ac4 3936\r
252d9457 3937 if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) {\r
3938 return (EFI_DEVICE_ERROR);\r
3939 }\r
3940\r
3941 Result = MultU64x32(Result, 10) + (*String - L'0');\r
3942 String++;\r
3943\r
3944 //\r
3945 // Stop at spaces if requested\r
3946 //\r
3947 if (StopAtSpace && *String == L' ') {\r
3948 break;\r
3949 }\r
3950 }\r
3951\r
3952 *Value = Result;\r
b0934ac4 3953\r
252d9457 3954 return (EFI_SUCCESS);\r
3955}\r
3956\r
3957/**\r
3958 Function to verify and convert a string to its numerical value.\r
3959\r
3960 If Hex it must be preceeded with a 0x, 0X, or has ForceHex set TRUE.\r
3961\r
3962 @param[in] String The string to evaluate.\r
3963 @param[out] Value Upon a successful return the value of the conversion.\r
3964 @param[in] ForceHex TRUE - always assume hex.\r
3965 @param[in] StopAtSpace FALSE to skip spaces.\r
b0934ac4 3966\r
252d9457 3967 @retval EFI_SUCCESS The conversion was successful.\r
3968 @retval EFI_INVALID_PARAMETER String contained an invalid character.\r
3969 @retval EFI_NOT_FOUND String was a number, but Value was NULL.\r
3970**/\r
3971EFI_STATUS\r
3972EFIAPI\r
3973ShellConvertStringToUint64(\r
3974 IN CONST CHAR16 *String,\r
3975 OUT UINT64 *Value,\r
3976 IN CONST BOOLEAN ForceHex,\r
3977 IN CONST BOOLEAN StopAtSpace\r
3978 )\r
3979{\r
3980 UINT64 RetVal;\r
3981 CONST CHAR16 *Walker;\r
3982 EFI_STATUS Status;\r
3983 BOOLEAN Hex;\r
3984\r
3985 Hex = ForceHex;\r
3986\r
658bf43e 3987 if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {\r
252d9457 3988 if (!Hex) {\r
3989 Hex = TRUE;\r
658bf43e 3990 if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {\r
252d9457 3991 return (EFI_INVALID_PARAMETER);\r
3992 }\r
3993 } else {\r
3994 return (EFI_INVALID_PARAMETER);\r
3995 }\r
3996 }\r
3997\r
3998 //\r
3999 // Chop off leading spaces\r
4000 //\r
4001 for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);\r
4002\r
4003 //\r
4004 // make sure we have something left that is numeric.\r
4005 //\r
658bf43e 4006 if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) {\r
252d9457 4007 return (EFI_INVALID_PARAMETER);\r
b0934ac4 4008 }\r
252d9457 4009\r
4010 //\r
4011 // do the conversion.\r
4012 //\r
4013 if (Hex || StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){\r
4014 Status = InternalShellStrHexToUint64(Walker, &RetVal, StopAtSpace);\r
4015 } else {\r
4016 Status = InternalShellStrDecimalToUint64(Walker, &RetVal, StopAtSpace);\r
4017 }\r
4018\r
4019 if (Value == NULL && !EFI_ERROR(Status)) {\r
4020 return (EFI_NOT_FOUND);\r
4021 }\r
4022\r
4023 if (Value != NULL) {\r
4024 *Value = RetVal;\r
4025 }\r
4026\r
4027 return (Status);\r
4028}\r
4029\r
4030/**\r
4031 Function to determin if an entire string is a valid number.\r
4032\r
4033 If Hex it must be preceeded with a 0x or has ForceHex, set TRUE.\r
4034\r
4035 @param[in] String The string to evaluate.\r
4036 @param[in] ForceHex TRUE - always assume hex.\r
4037 @param[in] StopAtSpace TRUE to halt upon finding a space, FALSE to keep going.\r
4038\r
4039 @retval TRUE It is all numeric (dec/hex) characters.\r
4040 @retval FALSE There is a non-numeric character.\r
4041**/\r
4042BOOLEAN\r
4043EFIAPI\r
4044ShellIsHexOrDecimalNumber (\r
4045 IN CONST CHAR16 *String,\r
4046 IN CONST BOOLEAN ForceHex,\r
4047 IN CONST BOOLEAN StopAtSpace\r
4048 )\r
4049{\r
4050 if (ShellConvertStringToUint64(String, NULL, ForceHex, StopAtSpace) == EFI_NOT_FOUND) {\r
4051 return (TRUE);\r
4052 }\r
4053 return (FALSE);\r
4054}\r
4d0a4fce 4055\r
4056/**\r
4057 Function to read a single line from a SHELL_FILE_HANDLE. The \n is not included in the returned\r
4058 buffer. The returned buffer must be callee freed.\r
4059\r
4060 If the position upon start is 0, then the Ascii Boolean will be set. This should be\r
4061 maintained and not changed for all operations with the same file.\r
4062\r
4ff7e37b
ED
4063 @param[in] Handle SHELL_FILE_HANDLE to read from.\r
4064 @param[in, out] Ascii Boolean value for indicating whether the file is\r
4065 Ascii (TRUE) or UCS2 (FALSE).\r
4d0a4fce 4066\r
beab0fc5 4067 @return The line of text from the file.\r
4068 @retval NULL There was not enough memory available.\r
4d0a4fce 4069\r
4070 @sa ShellFileHandleReadLine\r
4071**/\r
4072CHAR16*\r
4073EFIAPI\r
4074ShellFileHandleReturnLine(\r
4075 IN SHELL_FILE_HANDLE Handle,\r
4076 IN OUT BOOLEAN *Ascii\r
4077 )\r
4078{\r
4079 CHAR16 *RetVal;\r
4080 UINTN Size;\r
4081 EFI_STATUS Status;\r
4082\r
4083 Size = 0;\r
4084 RetVal = NULL;\r
4085\r
4086 Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);\r
4087 if (Status == EFI_BUFFER_TOO_SMALL) {\r
4088 RetVal = AllocateZeroPool(Size);\r
beab0fc5 4089 if (RetVal == NULL) {\r
4090 return (NULL);\r
4091 }\r
4d0a4fce 4092 Status = ShellFileHandleReadLine(Handle, RetVal, &Size, FALSE, Ascii);\r
b0934ac4 4093\r
4d0a4fce 4094 }\r
e3b76f3b 4095 if (Status == EFI_END_OF_FILE && RetVal != NULL && *RetVal != CHAR_NULL) {\r
f79d7b62
QS
4096 Status = EFI_SUCCESS;\r
4097 }\r
4d0a4fce 4098 if (EFI_ERROR(Status) && (RetVal != NULL)) {\r
4099 FreePool(RetVal);\r
4100 RetVal = NULL;\r
4101 }\r
4102 return (RetVal);\r
4103}\r
4104\r
4105/**\r
4106 Function to read a single line (up to but not including the \n) from a SHELL_FILE_HANDLE.\r
4107\r
4108 If the position upon start is 0, then the Ascii Boolean will be set. This should be\r
4109 maintained and not changed for all operations with the same file.\r
4110\r
2dda8a12
JD
4111 NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ\r
4112 IS IN ASCII FORMAT.\r
4113\r
4ff7e37b 4114 @param[in] Handle SHELL_FILE_HANDLE to read from.\r
2dda8a12
JD
4115 @param[in, out] Buffer The pointer to buffer to read into. If this function\r
4116 returns EFI_SUCCESS, then on output Buffer will\r
4117 contain a UCS2 string, even if the file being\r
4118 read is ASCII.\r
4119 @param[in, out] Size On input, pointer to number of bytes in Buffer.\r
4120 On output, unchanged unless Buffer is too small\r
4121 to contain the next line of the file. In that\r
4122 case Size is set to the number of bytes needed\r
4123 to hold the next line of the file (as a UCS2\r
4124 string, even if it is an ASCII file).\r
4ff7e37b
ED
4125 @param[in] Truncate If the buffer is large enough, this has no effect.\r
4126 If the buffer is is too small and Truncate is TRUE,\r
4127 the line will be truncated.\r
4128 If the buffer is is too small and Truncate is FALSE,\r
4129 then no read will occur.\r
4130\r
4131 @param[in, out] Ascii Boolean value for indicating whether the file is\r
4132 Ascii (TRUE) or UCS2 (FALSE).\r
4d0a4fce 4133\r
4134 @retval EFI_SUCCESS The operation was successful. The line is stored in\r
4135 Buffer.\r
9ed21946 4136 @retval EFI_END_OF_FILE There are no more lines in the file.\r
4d0a4fce 4137 @retval EFI_INVALID_PARAMETER Handle was NULL.\r
4138 @retval EFI_INVALID_PARAMETER Size was NULL.\r
4139 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.\r
4140 Size was updated to the minimum space required.\r
4141**/\r
4142EFI_STATUS\r
4143EFIAPI\r
4144ShellFileHandleReadLine(\r
4145 IN SHELL_FILE_HANDLE Handle,\r
4146 IN OUT CHAR16 *Buffer,\r
4147 IN OUT UINTN *Size,\r
4148 IN BOOLEAN Truncate,\r
4149 IN OUT BOOLEAN *Ascii\r
4150 )\r
4151{\r
4152 EFI_STATUS Status;\r
4153 CHAR16 CharBuffer;\r
4154 UINTN CharSize;\r
4155 UINTN CountSoFar;\r
4156 UINT64 OriginalFilePosition;\r
4157\r
4158\r
4159 if (Handle == NULL\r
4160 ||Size == NULL\r
4161 ){\r
4162 return (EFI_INVALID_PARAMETER);\r
4163 }\r
4164 if (Buffer == NULL) {\r
4165 ASSERT(*Size == 0);\r
4166 } else {\r
4167 *Buffer = CHAR_NULL;\r
4168 }\r
4169 gEfiShellProtocol->GetFilePosition(Handle, &OriginalFilePosition);\r
4170 if (OriginalFilePosition == 0) {\r
4171 CharSize = sizeof(CHAR16);\r
4172 Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);\r
4173 ASSERT_EFI_ERROR(Status);\r
4174 if (CharBuffer == gUnicodeFileTag) {\r
4175 *Ascii = FALSE;\r
4176 } else {\r
4177 *Ascii = TRUE;\r
4178 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
4179 }\r
4180 }\r
4181\r
9ed21946 4182 if (*Ascii) {\r
4183 CharSize = sizeof(CHAR8);\r
4184 } else {\r
4185 CharSize = sizeof(CHAR16);\r
4186 }\r
4d0a4fce 4187 for (CountSoFar = 0;;CountSoFar++){\r
4188 CharBuffer = 0;\r
4d0a4fce 4189 Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);\r
4190 if ( EFI_ERROR(Status)\r
4191 || CharSize == 0\r
4192 || (CharBuffer == L'\n' && !(*Ascii))\r
4193 || (CharBuffer == '\n' && *Ascii)\r
4194 ){\r
9ed21946 4195 if (CharSize == 0) {\r
4196 Status = EFI_END_OF_FILE;\r
4197 }\r
4d0a4fce 4198 break;\r
4199 }\r
4200 //\r
4201 // if we have space save it...\r
4202 //\r
1095b432 4203 if ((CountSoFar+1)*sizeof(CHAR16) < *Size){\r
4d0a4fce 4204 ASSERT(Buffer != NULL);\r
1095b432
JD
4205 ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
4206 ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
4d0a4fce 4207 }\r
4208 }\r
4209\r
4210 //\r
4211 // if we ran out of space tell when...\r
4212 //\r
1095b432
JD
4213 if ((CountSoFar+1)*sizeof(CHAR16) > *Size){\r
4214 *Size = (CountSoFar+1)*sizeof(CHAR16);\r
4215 if (!Truncate) {\r
4216 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
4217 } else {\r
4218 DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
4d0a4fce 4219 }\r
1095b432
JD
4220 return (EFI_BUFFER_TOO_SMALL);\r
4221 }\r
4222 while(Buffer[StrLen(Buffer)-1] == L'\r') {\r
4223 Buffer[StrLen(Buffer)-1] = CHAR_NULL;\r
4d0a4fce 4224 }\r
4225\r
4226 return (Status);\r
4227}\r
fb5278ef 4228\r
365aa98a 4229/**\r
4230 Function to print help file / man page content in the spec from the UEFI Shell protocol GetHelpText function.\r
4231\r
4232 @param[in] CommandToGetHelpOn Pointer to a string containing the command name of help file to be printed.\r
4233 @param[in] SectionToGetHelpOn Pointer to the section specifier(s).\r
ba0014b9 4234 @param[in] PrintCommandText If TRUE, prints the command followed by the help content, otherwise prints\r
365aa98a 4235 the help content only.\r
4236 @retval EFI_DEVICE_ERROR The help data format was incorrect.\r
4237 @retval EFI_NOT_FOUND The help data could not be found.\r
4238 @retval EFI_SUCCESS The operation was successful.\r
4239**/\r
4240EFI_STATUS\r
4241EFIAPI\r
4242ShellPrintHelp (\r
4243 IN CONST CHAR16 *CommandToGetHelpOn,\r
4244 IN CONST CHAR16 *SectionToGetHelpOn,\r
4245 IN BOOLEAN PrintCommandText\r
4246 )\r
4247{\r
ba0014b9
LG
4248 EFI_STATUS Status;\r
4249 CHAR16 *OutText;\r
4250\r
4251 OutText = NULL;\r
4252\r
365aa98a 4253 //\r
4254 // Get the string to print based\r
4255 //\r
ba0014b9
LG
4256 Status = gEfiShellProtocol->GetHelpText (CommandToGetHelpOn, SectionToGetHelpOn, &OutText);\r
4257\r
365aa98a 4258 //\r
4259 // make sure we got a valid string\r
4260 //\r
4261 if (EFI_ERROR(Status)){\r
4262 return Status;\r
ba0014b9 4263 }\r
365aa98a 4264 if (OutText == NULL || StrLen(OutText) == 0) {\r
ba0014b9
LG
4265 return EFI_NOT_FOUND;\r
4266 }\r
4267\r
365aa98a 4268 //\r
4269 // Chop off trailing stuff we dont need\r
4270 //\r
4271 while (OutText[StrLen(OutText)-1] == L'\r' || OutText[StrLen(OutText)-1] == L'\n' || OutText[StrLen(OutText)-1] == L' ') {\r
4272 OutText[StrLen(OutText)-1] = CHAR_NULL;\r
4273 }\r
ba0014b9 4274\r
365aa98a 4275 //\r
4276 // Print this out to the console\r
4277 //\r
4278 if (PrintCommandText) {\r
4279 ShellPrintEx(-1, -1, L"%H%-14s%N- %s\r\n", CommandToGetHelpOn, OutText);\r
4280 } else {\r
4281 ShellPrintEx(-1, -1, L"%N%s\r\n", OutText);\r
4282 }\r
ba0014b9 4283\r
365aa98a 4284 SHELL_FREE_NON_NULL(OutText);\r
4285\r
ba0014b9 4286 return EFI_SUCCESS;\r
365aa98a 4287}\r
4288\r
fb5278ef 4289/**\r
4290 Function to delete a file by name\r
ba0014b9 4291\r
fb5278ef 4292 @param[in] FileName Pointer to file name to delete.\r
ba0014b9 4293\r
fb5278ef 4294 @retval EFI_SUCCESS the file was deleted sucessfully\r
4295 @retval EFI_WARN_DELETE_FAILURE the handle was closed, but the file was not\r
4296 deleted\r
4297 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
4298 @retval EFI_NOT_FOUND The specified file could not be found on the\r
4299 device or the file system could not be found\r
4300 on the device.\r
4301 @retval EFI_NO_MEDIA The device has no medium.\r
4302 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the\r
4303 medium is no longer supported.\r
4304 @retval EFI_DEVICE_ERROR The device reported an error.\r
4305 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
4306 @retval EFI_WRITE_PROTECTED The file or medium is write protected.\r
4307 @retval EFI_ACCESS_DENIED The file was opened read only.\r
4308 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the\r
4309 file.\r
4310 @retval other The file failed to open\r
4311**/\r
4312EFI_STATUS\r
4313EFIAPI\r
4314ShellDeleteFileByName(\r
4315 IN CONST CHAR16 *FileName\r
4316 )\r
4317{\r
4318 EFI_STATUS Status;\r
4319 SHELL_FILE_HANDLE FileHandle;\r
ba0014b9 4320\r
fb5278ef 4321 Status = ShellFileExists(FileName);\r
ba0014b9 4322\r
fb5278ef 4323 if (Status == EFI_SUCCESS){\r
4324 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0x0);\r
4325 if (Status == EFI_SUCCESS){\r
4326 Status = ShellDeleteFile(&FileHandle);\r
4327 }\r
ba0014b9 4328 }\r
fb5278ef 4329\r
4330 return(Status);\r
ba0014b9 4331\r
fb5278ef 4332}\r
0960ba17
QS
4333\r
4334/**\r
4335 Cleans off all the quotes in the string.\r
4336\r
4337 @param[in] OriginalString pointer to the string to be cleaned.\r
ba0014b9
LG
4338 @param[out] CleanString The new string with all quotes removed.\r
4339 Memory allocated in the function and free\r
0960ba17
QS
4340 by caller.\r
4341\r
4342 @retval EFI_SUCCESS The operation was successful.\r
4343**/\r
4344EFI_STATUS\r
0960ba17
QS
4345InternalShellStripQuotes (\r
4346 IN CONST CHAR16 *OriginalString,\r
4347 OUT CHAR16 **CleanString\r
4348 )\r
4349{\r
4350 CHAR16 *Walker;\r
ba0014b9 4351\r
0960ba17
QS
4352 if (OriginalString == NULL || CleanString == NULL) {\r
4353 return EFI_INVALID_PARAMETER;\r
4354 }\r
4355\r
4356 *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);\r
4357 if (*CleanString == NULL) {\r
4358 return EFI_OUT_OF_RESOURCES;\r
4359 }\r
4360\r
4361 for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
4362 if (*Walker == L'\"') {\r
4363 CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
4364 }\r
4365 }\r
4366\r
4367 return EFI_SUCCESS;\r
4368}\r
4369\r