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