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