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