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