]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLib/UefiShellLib.c
updating headers from code review.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLib / UefiShellLib.c
index 7b7533a32739ec92fcb4e066aef914148f49077d..f0b1e95b5fea0c4a656a736f9072bc5b4617e4a8 100644 (file)
@@ -24,6 +24,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/FileHandleLib.h>\r
 #include <Library/PrintLib.h>\r
 #include <Library/UefiLib.h>\r
+#include <Library/HiiLib.h>\r
 \r
 #include <Protocol/EfiShellEnvironment2.h>\r
 #include <Protocol/EfiShellInterface.h>\r
@@ -52,6 +53,29 @@ STATIC EFI_SHELL_PROTOCOL            *mEfiShellProtocol;
 STATIC EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol;\r
 STATIC EFI_HANDLE                    mEfiShellEnvironment2Handle;\r
 STATIC FILE_HANDLE_FUNCTION_MAP      FileFunctionMap;\r
+STATIC UINTN                         mTotalParameterCount;\r
+\r
+/**\r
+  Check if a Unicode character is a hexadecimal character.\r
+\r
+  This internal function checks if a Unicode character is a \r
+  decimal character.  The valid hexadecimal character is \r
+  L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
+\r
+\r
+  @param  Char  The character to check against.\r
+\r
+  @retval TRUE  If the Char is a hexadecmial character.\r
+  @retval FALSE If the Char is not a hexadecmial character.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+ShellInternalIsHexaDecimalDigitCharacter (\r
+  IN      CHAR16                    Char\r
+  ) {\r
+  return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
+}\r
 \r
 /**\r
   helper function to find ShellEnvironment2 for constructor\r
@@ -60,8 +84,7 @@ EFI_STATUS
 EFIAPI\r
 ShellFindSE2 (\r
   IN EFI_HANDLE        ImageHandle\r
-  )\r
-{\r
+  ) {\r
   EFI_STATUS  Status;\r
   EFI_HANDLE  *Buffer;\r
   UINTN       BufferSize;\r
@@ -89,15 +112,19 @@ ShellFindSE2 (
                                 &BufferSize,\r
                                 Buffer\r
                                 );\r
-    ASSERT(Status == EFI_BUFFER_TOO_SMALL);\r
-    Buffer = (EFI_HANDLE*)AllocatePool(BufferSize);\r
-    ASSERT(Buffer != NULL);\r
-    Status = gBS->LocateHandle (ByProtocol,\r
-                                &gEfiShellEnvironment2Guid,\r
-                                NULL, // ignored for ByProtocol\r
-                                &BufferSize,\r
-                                Buffer\r
-                                );\r
+    //\r
+    // maybe it's not there???\r
+    //\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Buffer = (EFI_HANDLE*)AllocatePool(BufferSize);\r
+      ASSERT(Buffer != NULL);\r
+      Status = gBS->LocateHandle (ByProtocol,\r
+                                  &gEfiShellEnvironment2Guid,\r
+                                  NULL, // ignored for ByProtocol\r
+                                  &BufferSize,\r
+                                  Buffer\r
+                                  );\r
+    }\r
     if (!EFI_ERROR (Status)) {\r
       //\r
       // now parse the list of returned handles\r
@@ -130,9 +157,14 @@ EFIAPI
 ShellLibConstructorWorker (\r
   IN EFI_HANDLE        ImageHandle,\r
   IN EFI_SYSTEM_TABLE  *SystemTable\r
-){\r
+  ) {\r
   EFI_STATUS Status;\r
 \r
+  //\r
+  // Set the parameter count to an invalid number\r
+  //\r
+  mTotalParameterCount = (UINTN)(-1);\r
+\r
   //\r
   // UEFI 2.0 shell interfaces (used preferentially)\r
   //\r
@@ -226,8 +258,7 @@ EFIAPI
 ShellLibConstructor (\r
   IN EFI_HANDLE        ImageHandle,\r
   IN EFI_SYSTEM_TABLE  *SystemTable\r
-  )\r
-{\r
+  ) {\r
 \r
 \r
   mEfiShellEnvironment2       = NULL;\r
@@ -254,7 +285,7 @@ EFIAPI
 ShellLibDestructor (\r
   IN EFI_HANDLE        ImageHandle,\r
   IN EFI_SYSTEM_TABLE  *SystemTable\r
-  ){\r
+  ) {\r
   if (mEfiShellEnvironment2 != NULL) {\r
     gBS->CloseProtocol(mEfiShellEnvironment2Handle==NULL?ImageHandle:mEfiShellEnvironment2Handle,\r
                        &gEfiShellEnvironment2Guid,\r
@@ -340,8 +371,7 @@ EFI_FILE_INFO*
 EFIAPI\r
 ShellGetFileInfo (\r
   IN EFI_FILE_HANDLE            FileHandle\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.GetFileInfo(FileHandle));\r
 }\r
 \r
@@ -368,8 +398,7 @@ EFIAPI
 ShellSetFileInfo (\r
   IN EFI_FILE_HANDLE           FileHandle,\r
   IN EFI_FILE_INFO              *FileInfo\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo));\r
 }  \r
   \r
@@ -411,8 +440,7 @@ ShellOpenFileByDevicePath(
   OUT EFI_FILE_HANDLE                  *FileHandle,\r
   IN UINT64                            OpenMode,\r
   IN UINT64                            Attributes\r
-  )\r
-{\r
+  ) {\r
   CHAR16      *FileName;\r
   EFI_STATUS  Status;\r
   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;\r
@@ -562,8 +590,7 @@ ShellOpenFileByName(
   OUT EFI_FILE_HANDLE           *FileHandle,\r
   IN UINT64                     OpenMode,\r
   IN UINT64                            Attributes\r
-  )\r
-{\r
+  ) {\r
   EFI_HANDLE                    DeviceHandle;\r
   EFI_DEVICE_PATH_PROTOCOL      *FilePath;\r
   EFI_STATUS                    Status;\r
@@ -581,11 +608,12 @@ ShellOpenFileByName(
     Status = mEfiShellProtocol->OpenFileByName(FileName,\r
                                                FileHandle,\r
                                                OpenMode);\r
-    if (!EFI_ERROR(Status)){\r
-      FileInfo = FileHandleGetInfo(*FileHandle);\r
+    if (!EFI_ERROR(Status) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)){\r
+      FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);\r
       ASSERT(FileInfo != NULL);\r
       FileInfo->Attribute = Attributes;\r
-      Status = FileHandleSetInfo(*FileHandle, FileInfo);\r
+      Status = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);\r
+      FreePool(FileInfo);\r
     }\r
     return (Status);\r
   } \r
@@ -638,16 +666,22 @@ EFIAPI
 ShellCreateDirectory(\r
   IN CONST CHAR16             *DirectoryName,\r
   OUT EFI_FILE_HANDLE         *FileHandle\r
-  )\r
-{\r
-  //\r
-  // this is a pass thru to the open file function with sepcific open mode and attributes\r
-  //\r
-  return (ShellOpenFileByName(DirectoryName,\r
-                              FileHandle,\r
-                              EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
-                              EFI_FILE_DIRECTORY\r
-                              ));\r
+  ) {\r
+  if (mEfiShellProtocol != NULL) {\r
+    //\r
+    // Use UEFI Shell 2.0 method\r
+    //\r
+    return (mEfiShellProtocol->CreateFile(DirectoryName,\r
+                          EFI_FILE_DIRECTORY,\r
+                          FileHandle\r
+                          ));\r
+  } else {\r
+    return (ShellOpenFileByName(DirectoryName,\r
+                                FileHandle,\r
+                                EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
+                                EFI_FILE_DIRECTORY\r
+                                ));\r
+  }\r
 }\r
 \r
 /**\r
@@ -685,8 +719,7 @@ ShellReadFile(
   IN EFI_FILE_HANDLE            FileHandle,\r
   IN OUT UINTN                  *BufferSize,\r
   OUT VOID                      *Buffer\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer));\r
 }\r
 \r
@@ -721,8 +754,7 @@ ShellWriteFile(
   IN EFI_FILE_HANDLE            FileHandle,\r
   IN OUT UINTN                  *BufferSize,\r
   IN VOID                       *Buffer\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer));\r
 }\r
 \r
@@ -741,8 +773,7 @@ EFI_STATUS
 EFIAPI\r
 ShellCloseFile (\r
   IN EFI_FILE_HANDLE            *FileHandle\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.CloseFile(*FileHandle));\r
 }\r
 \r
@@ -764,8 +795,7 @@ EFI_STATUS
 EFIAPI\r
 ShellDeleteFile (\r
   IN EFI_FILE_HANDLE           *FileHandle\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.DeleteFile(*FileHandle));\r
 }\r
 \r
@@ -793,8 +823,7 @@ EFIAPI
 ShellSetFilePosition (\r
   IN EFI_FILE_HANDLE           FileHandle,\r
   IN UINT64            Position\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.SetFilePosition(FileHandle, Position));\r
 }\r
 \r
@@ -818,8 +847,7 @@ EFIAPI
 ShellGetFilePosition (\r
   IN EFI_FILE_HANDLE            FileHandle,\r
   OUT UINT64                    *Position\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.GetFilePosition(FileHandle, Position));\r
 }\r
 /**\r
@@ -840,8 +868,7 @@ EFI_STATUS
 EFIAPI\r
 ShellFlushFile (\r
   IN EFI_FILE_HANDLE            FileHandle\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.FlushFile(FileHandle));\r
 }\r
 \r
@@ -868,8 +895,7 @@ EFIAPI
 ShellFindFirstFile (\r
   IN EFI_FILE_HANDLE            DirHandle,\r
   OUT EFI_FILE_INFO             **Buffer\r
-  )\r
-{\r
+  ) {\r
   //\r
   // pass to file handle lib\r
   //\r
@@ -900,8 +926,7 @@ ShellFindNextFile(
   IN EFI_FILE_HANDLE             DirHandle,\r
   OUT EFI_FILE_INFO              *Buffer,\r
   OUT BOOLEAN                    *NoFile\r
-  )\r
-{\r
+  ) {\r
   //\r
   // pass to file handle lib\r
   //\r
@@ -927,8 +952,7 @@ EFIAPI
 ShellGetFileSize (\r
   IN EFI_FILE_HANDLE            FileHandle,\r
   OUT UINT64                    *Size\r
-  )\r
-{\r
+  ) {\r
   return (FileFunctionMap.GetFileSize(FileHandle, Size));\r
 }\r
 /**\r
@@ -1225,7 +1249,8 @@ EFIAPI
 InternalShellConvertFileListType (\r
   IN LIST_ENTRY                 *FileList,\r
   IN OUT LIST_ENTRY             *ListHead\r
-  ){\r
+  )\r
+{\r
   SHELL_FILE_ARG                *OldInfo;\r
   LIST_ENTRY                    *Link;\r
   EFI_SHELL_FILE_INFO_NO_CONST  *NewInfo;\r
@@ -1302,7 +1327,8 @@ InternalShellConvertFileListType (
   and will process '?' and '*' as such.  the list must be freed with a call to \r
   ShellCloseFileMetaArg().\r
 \r
-  If you are NOT appending to an existing list *ListHead must be NULL.\r
+  If you are NOT appending to an existing list *ListHead must be NULL.  If \r
+  *ListHead is NULL then it must be callee freed.\r
 \r
   @param Arg                    pointer to path string\r
   @param OpenMode               mode to open files with\r
@@ -1337,9 +1363,22 @@ ShellOpenFileMetaArg (
   // Check for UEFI Shell 2.0 protocols\r
   //\r
   if (mEfiShellProtocol != NULL) {\r
-    return (mEfiShellProtocol->OpenFileList(Arg, \r
+    if (*ListHead == NULL) {\r
+      *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
+      if (*ListHead == NULL) {\r
+        return (EFI_OUT_OF_RESOURCES);\r
+      }\r
+      InitializeListHead(&((*ListHead)->Link));\r
+    }    \r
+    Status = mEfiShellProtocol->OpenFileList(Arg, \r
                                            OpenMode, \r
-                                           ListHead));\r
+                                           ListHead);\r
+    if (EFI_ERROR(Status)) {\r
+      mEfiShellProtocol->RemoveDupInFileList(ListHead);\r
+    } else {\r
+      Status = mEfiShellProtocol->RemoveDupInFileList(ListHead);\r
+    }\r
+    return (Status);\r
   } \r
 \r
   //\r
@@ -1426,6 +1465,74 @@ ShellCloseFileMetaArg (
   }\r
 }\r
 \r
+/**\r
+  Find a file by searching the CWD and then the path.\r
+\r
+  if FileName is NULL then ASSERT.\r
+\r
+  if the return value is not NULL then the memory must be caller freed.\r
+\r
+  @param FileName               Filename string.\r
+\r
+  @retval NULL                  the file was not found\r
+  @return !NULL                 the full path to the file.\r
+**/\r
+CHAR16 *\r
+EFIAPI\r
+ShellFindFilePath (\r
+  IN CONST CHAR16 *FileName\r
+  )\r
+{\r
+  CONST CHAR16      *Path;\r
+  EFI_FILE_HANDLE   Handle;\r
+  EFI_STATUS        Status;\r
+  CHAR16            *RetVal;\r
+  CHAR16            *TestPath;\r
+  CONST CHAR16      *Walker;\r
+\r
+  RetVal = NULL;\r
+\r
+  Path = ShellGetEnvironmentVariable(L"cwd");\r
+  if (Path != NULL) {\r
+    TestPath = AllocateZeroPool(StrSize(Path) + StrSize(FileName));\r
+    StrCpy(TestPath, Path);\r
+    StrCat(TestPath, FileName);\r
+    Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
+    if (!EFI_ERROR(Status)){\r
+      RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);\r
+      ShellCloseFile(&Handle);\r
+      FreePool(TestPath);\r
+      return (RetVal);\r
+    }\r
+    FreePool(TestPath);\r
+  }\r
+  Path = ShellGetEnvironmentVariable(L"path");\r
+  if (Path != NULL) {\r
+    TestPath = AllocateZeroPool(StrSize(Path)+StrSize(FileName) );\r
+    Walker = (CHAR16*)Path; \r
+    do {\r
+      CopyMem(TestPath, Walker, StrSize(Walker));\r
+      if (StrStr(TestPath, L";") != NULL) {\r
+        *(StrStr(TestPath, L";")) = CHAR_NULL;\r
+      }\r
+      StrCat(TestPath, FileName);\r
+      if (StrStr(Walker, L";") != NULL) {\r
+        Walker = StrStr(Walker, L";") + 1;\r
+      } else {\r
+        Walker = NULL;\r
+      }\r
+      Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
+      if (!EFI_ERROR(Status)){\r
+        RetVal = StrnCatGrow(&RetVal, NULL, TestPath, 0);\r
+        ShellCloseFile(&Handle);\r
+        break;\r
+      }\r
+    } while (Walker != NULL && Walker[0] != CHAR_NULL);\r
+    FreePool(TestPath);\r
+  }\r
+  return (RetVal);\r
+}\r
+\r
 typedef struct {\r
   LIST_ENTRY     Link;\r
   CHAR16         *Name;\r
@@ -1455,8 +1562,7 @@ InternalIsOnCheckList (
   IN CONST CHAR16               *Name,\r
   IN CONST SHELL_PARAM_ITEM     *CheckList,\r
   OUT ParamType                 *Type\r
-  )\r
-{\r
+  ) {\r
   SHELL_PARAM_ITEM              *TempListItem;\r
 \r
   //\r
@@ -1491,6 +1597,7 @@ InternalIsOnCheckList (
       return (TRUE);\r
     }\r
   }\r
+\r
   return (FALSE);\r
 }\r
 /**\r
@@ -1504,7 +1611,8 @@ InternalIsOnCheckList (
 BOOLEAN\r
 EFIAPI\r
 InternalIsFlag (\r
-  IN CONST CHAR16               *Name\r
+  IN CONST CHAR16               *Name,\r
+  IN BOOLEAN                    AlwaysAllowNumbers\r
   )\r
 {\r
   //\r
@@ -1512,6 +1620,13 @@ InternalIsFlag (
   //\r
   ASSERT(Name != NULL);\r
 \r
+  //\r
+  // If we accept numbers then dont return TRUE. (they will be values)\r
+  //\r
+  if (((Name[0] == L'-' || Name[0] == L'+') && ShellInternalIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers == TRUE) {\r
+    return (FALSE);\r
+  }\r
+\r
   //\r
   // If the Name has a / or - as the first character return TRUE\r
   //\r
@@ -1548,6 +1663,7 @@ InternalIsFlag (
                                 the invalid command line argument was returned in\r
                                 ProblemParam if provided.\r
 **/\r
+STATIC\r
 EFI_STATUS\r
 EFIAPI\r
 InternalCommandLineParse (\r
@@ -1556,25 +1672,19 @@ InternalCommandLineParse (
   OUT CHAR16                    **ProblemParam OPTIONAL,\r
   IN BOOLEAN                    AutoPageBreak,\r
   IN CONST CHAR16               **Argv,\r
-  IN UINTN                      Argc\r
-  )\r
-{\r
+  IN UINTN                      Argc,\r
+  IN BOOLEAN                    AlwaysAllowNumbers\r
+  ) {\r
   UINTN                         LoopCounter;\r
-  UINTN                         Count;\r
   ParamType                     CurrentItemType;\r
   SHELL_PARAM_PACKAGE           *CurrentItemPackage;\r
-  BOOLEAN                       GetItemValue;\r
+  UINTN                         GetItemValue;\r
+  UINTN                         ValueSize;\r
 \r
   CurrentItemPackage = NULL;\r
-\r
-  //\r
-  // ASSERTs\r
-  //\r
-  ASSERT(CheckList  != NULL);\r
-  ASSERT(Argv       != NULL);\r
-\r
-  Count = 0;\r
-  GetItemValue = FALSE;\r
+  mTotalParameterCount = 0;\r
+  GetItemValue = 0;\r
+  ValueSize = 0;\r
 \r
   //\r
   // If there is only 1 item we dont need to do anything\r
@@ -1584,6 +1694,12 @@ InternalCommandLineParse (
     return (EFI_SUCCESS);\r
   }\r
 \r
+  //\r
+  // ASSERTs\r
+  //\r
+  ASSERT(CheckList  != NULL);\r
+  ASSERT(Argv       != NULL);\r
+\r
   //\r
   // initialize the linked list\r
   //\r
@@ -1599,6 +1715,13 @@ InternalCommandLineParse (
       // do nothing for NULL argv\r
       //\r
     } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) {\r
+      //\r
+      // We might have leftover if last parameter didnt have optional value\r
+      //\r
+      if (GetItemValue != 0) {\r
+        GetItemValue = 0;\r
+        InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+      }\r
       //\r
       // this is a flag\r
       //\r
@@ -1614,28 +1737,49 @@ InternalCommandLineParse (
       //\r
       // Does this flag require a value\r
       //\r
-      if (CurrentItemPackage->Type == TypeValue) {\r
-        //\r
-        // trigger the next loop to populate the value of this item\r
-        //\r
-        GetItemValue = TRUE; \r
-      } else {\r
-        //\r
-        // this item has no value expected; we are done\r
+      switch (CurrentItemPackage->Type) {\r
         //\r
-        InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+        // possibly trigger the next loop(s) to populate the value of this item\r
+        //        \r
+        case TypeValue:\r
+          GetItemValue = 1; \r
+          ValueSize = 0;\r
+          break;\r
+        case TypeDoubleValue:\r
+          GetItemValue = 2;\r
+          ValueSize = 0;\r
+          break;\r
+        case TypeMaxValue:\r
+          GetItemValue = (UINTN)(-1);\r
+          ValueSize = 0;\r
+          break;\r
+        default:\r
+          //\r
+          // this item has no value expected; we are done\r
+          //\r
+          InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+          ASSERT(GetItemValue == 0);\r
+          break;\r
       }\r
-    } else if (GetItemValue == TRUE && InternalIsFlag(Argv[LoopCounter]) == FALSE) {\r
+    } else if (GetItemValue != 0 && InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) == FALSE) {\r
       ASSERT(CurrentItemPackage != NULL);\r
       //\r
-      // get the item VALUE for the previous flag\r
+      // get the item VALUE for a previous flag\r
       //\r
-      GetItemValue = FALSE;\r
-      CurrentItemPackage->Value = AllocateZeroPool(StrSize(Argv[LoopCounter]));\r
+      CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16), CurrentItemPackage->Value);\r
       ASSERT(CurrentItemPackage->Value != NULL);\r
-      StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-      InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
-    } else if (InternalIsFlag(Argv[LoopCounter]) == FALSE) {\r
+      if (ValueSize == 0) {\r
+        StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
+      } else {\r
+        StrCat(CurrentItemPackage->Value, L" ");\r
+        StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
+      }\r
+      ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+      GetItemValue--;\r
+      if (GetItemValue == 0) {\r
+        InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+      }\r
+    } else if (InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) == FALSE) {\r
       //\r
       // add this one as a non-flag\r
       //\r
@@ -1646,7 +1790,7 @@ InternalCommandLineParse (
       CurrentItemPackage->Value = AllocatePool(StrSize(Argv[LoopCounter]));\r
       ASSERT(CurrentItemPackage->Value != NULL);\r
       StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-      CurrentItemPackage->OriginalPosition = Count++;\r
+      CurrentItemPackage->OriginalPosition = mTotalParameterCount++;\r
       InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
     } else if (ProblemParam) {\r
       //\r
@@ -1664,6 +1808,10 @@ InternalCommandLineParse (
       return (EFI_VOLUME_CORRUPTED);\r
     }\r
   }\r
+  if (GetItemValue != 0) {\r
+    GetItemValue = 0;\r
+    InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
+  }\r
   //\r
   // support for AutoPageBreak\r
   //\r
@@ -1700,13 +1848,13 @@ InternalCommandLineParse (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-ShellCommandLineParse (\r
+ShellCommandLineParseEx (\r
   IN CONST SHELL_PARAM_ITEM     *CheckList,\r
   OUT LIST_ENTRY                **CheckPackage,\r
   OUT CHAR16                    **ProblemParam OPTIONAL,\r
-  IN BOOLEAN                    AutoPageBreak\r
-  )\r
-{\r
+  IN BOOLEAN                    AutoPageBreak,\r
+  IN BOOLEAN                    AlwaysAllowNumbers\r
+  ) {\r
   // \r
   // ASSERT that CheckList and CheckPackage aren't NULL\r
   //\r
@@ -1722,7 +1870,8 @@ ShellCommandLineParse (
                                      ProblemParam, \r
                                      AutoPageBreak, \r
                                      (CONST CHAR16**) mEfiShellParametersProtocol->Argv,\r
-                                     mEfiShellParametersProtocol->Argc ));\r
+                                     mEfiShellParametersProtocol->Argc,\r
+                                     AlwaysAllowNumbers));\r
   }\r
 \r
   // \r
@@ -1734,7 +1883,8 @@ ShellCommandLineParse (
                                    ProblemParam, \r
                                    AutoPageBreak, \r
                                    (CONST CHAR16**) mEfiShellInterface->Argv,\r
-                                   mEfiShellInterface->Argc ));\r
+                                   mEfiShellInterface->Argc,\r
+                                   AlwaysAllowNumbers));\r
 }\r
 \r
 /**\r
@@ -1753,8 +1903,7 @@ VOID
 EFIAPI\r
 ShellCommandLineFreeVarList (\r
   IN LIST_ENTRY                 *CheckPackage\r
-  )\r
-{\r
+  ) {\r
   LIST_ENTRY                    *Node;\r
 \r
   //\r
@@ -1768,7 +1917,7 @@ ShellCommandLineFreeVarList (
   // for each node in the list\r
   //\r
   for ( Node = GetFirstNode(CheckPackage)\r
-      ; Node != CheckPackage \r
+      ; IsListEmpty(CheckPackage) == FALSE\r
       ; Node = GetFirstNode(CheckPackage)\r
       ){\r
     //\r
@@ -1819,8 +1968,7 @@ EFIAPI
 ShellCommandLineGetFlag (\r
   IN CONST LIST_ENTRY           *CheckPackage,\r
   IN CHAR16                     *KeyString\r
-  )\r
-{\r
+  ) {\r
   LIST_ENTRY                    *Node;\r
 \r
   //\r
@@ -1878,8 +2026,7 @@ EFIAPI
 ShellCommandLineGetValue (\r
   IN CONST LIST_ENTRY           *CheckPackage,\r
   IN CHAR16                     *KeyString\r
-  )\r
-{\r
+  ) {\r
   LIST_ENTRY                    *Node;\r
 \r
   //\r
@@ -1938,8 +2085,7 @@ EFIAPI
 ShellCommandLineGetRawValue (\r
   IN CONST LIST_ENTRY           *CheckPackage,\r
   IN UINT32                     Position\r
-  )\r
-{\r
+  ) {\r
   LIST_ENTRY                    *Node;\r
 \r
   //\r
@@ -1965,6 +2111,24 @@ ShellCommandLineGetRawValue (
   }\r
   return (NULL);\r
 }\r
+\r
+/**\r
+  returns the number of command line value parameters that were parsed.  \r
+  \r
+  this will not include flags.\r
+\r
+  @retval (UINTN)-1     No parsing has ocurred\r
+  @return other         The number of value parameters found\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellCommandLineGetCount(\r
+  VOID\r
+  )\r
+{\r
+  return (mTotalParameterCount);\r
+}\r
+\r
 /**\r
   This is a find and replace function.  it will return the NewString as a copy of \r
   SourceString with each instance of FindTarget replaced with ReplaceWith.\r
@@ -1996,7 +2160,9 @@ CopyReplace(
   IN UINTN                            NewSize,\r
   IN CONST CHAR16                     *FindTarget,\r
   IN CONST CHAR16                     *ReplaceWith\r
-  ){\r
+  ) \r
+{\r
+  UINTN Size;\r
   if ( (SourceString == NULL)\r
     || (NewString    == NULL)\r
     || (FindTarget   == NULL)\r
@@ -2006,16 +2172,18 @@ CopyReplace(
     ){\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
-  NewString = SetMem16(NewString, NewSize, L'\0');\r
-  while (*SourceString != L'\0') {\r
+  NewString = SetMem16(NewString, NewSize, CHAR_NULL);\r
+  while (*SourceString != CHAR_NULL) {\r
     if (StrnCmp(SourceString, FindTarget, StrLen(FindTarget)) == 0) {\r
       SourceString += StrLen(FindTarget);\r
-      if ((StrSize(NewString) + (StrLen(ReplaceWith)*sizeof(CHAR16))) > NewSize) {\r
+      Size = StrSize(NewString);\r
+      if ((Size + (StrLen(ReplaceWith)*sizeof(CHAR16))) > NewSize) {\r
         return (EFI_BUFFER_TOO_SMALL);\r
       }\r
       StrCat(NewString, ReplaceWith);\r
     } else {\r
-      if (StrSize(NewString) + sizeof(CHAR16) > NewSize) {\r
+      Size = StrSize(NewString);\r
+      if (Size + sizeof(CHAR16) > NewSize) {\r
         return (EFI_BUFFER_TOO_SMALL);\r
       }\r
       StrnCat(NewString, SourceString, 1);\r
@@ -2049,30 +2217,28 @@ CopyReplace(
   @param[in] Row        the row to print at\r
   @param[in] Col        the column to print at\r
   @param[in] Format     the format string\r
+  @param[in] Marker     the marker for the variable argument list\r
 \r
   @return the number of characters printed to the screen\r
 **/\r
 \r
 UINTN\r
 EFIAPI\r
-ShellPrintEx(\r
+InternalShellPrintWorker(\r
   IN INT32                Col OPTIONAL,\r
   IN INT32                Row OPTIONAL,\r
   IN CONST CHAR16         *Format,\r
-  ...\r
-  ){\r
-  VA_LIST           Marker;\r
+  VA_LIST                 Marker\r
+  ) \r
+{\r
   UINTN             BufferSize;\r
   CHAR16            *PostReplaceFormat;\r
   CHAR16            *PostReplaceFormat2;\r
   UINTN             Return;\r
-\r
   EFI_STATUS        Status;\r
   UINTN             NormalAttribute;\r
   CHAR16            *ResumeLocation;\r
   CHAR16            *FormatWalker;\r
-\r
-  VA_START (Marker, Format);\r
   \r
   BufferSize = (PcdGet32 (PcdUefiLibMaxPrintBufferSize) + 1) * sizeof (CHAR16);\r
   PostReplaceFormat = AllocateZeroPool (BufferSize);\r
@@ -2108,13 +2274,13 @@ ShellPrintEx(
 \r
   NormalAttribute = gST->ConOut->Mode->Attribute;\r
   FormatWalker = PostReplaceFormat2;\r
-  while (*FormatWalker != L'\0') {\r
+  while (*FormatWalker != CHAR_NULL) {\r
     //\r
     // Find the next attribute change request\r
     //\r
     ResumeLocation = StrStr(FormatWalker, L"%");\r
     if (ResumeLocation != NULL) {\r
-      *ResumeLocation = L'\0';\r
+      *ResumeLocation = CHAR_NULL;\r
     }\r
     //\r
     // print the current FormatWalker string\r
@@ -2162,4 +2328,257 @@ ShellPrintEx(
   FreePool(PostReplaceFormat2);\r
 \r
   return (Return);\r
-}
\ No newline at end of file
+}\r
+\r
+/**\r
+  Print at a specific location on the screen.\r
+\r
+  This function will move the cursor to a given screen location and print the specified string\r
+  \r
+  If -1 is specified for either the Row or Col the current screen location for BOTH \r
+  will be used.\r
+\r
+  if either Row or Col is out of range for the current console, then ASSERT\r
+  if Format is NULL, then ASSERT\r
+\r
+  In addition to the standard %-based flags as supported by UefiLib Print() this supports \r
+  the following additional flags:\r
+    %N       -   Set output attribute to normal\r
+    %H       -   Set output attribute to highlight\r
+    %E       -   Set output attribute to error\r
+    %B       -   Set output attribute to blue color\r
+    %V       -   Set output attribute to green color\r
+\r
+  Note: The background color is controlled by the shell command cls.\r
+\r
+  @param[in] Row        the row to print at\r
+  @param[in] Col        the column to print at\r
+  @param[in] Format     the format string\r
+\r
+  @return the number of characters printed to the screen\r
+**/\r
+\r
+UINTN\r
+EFIAPI\r
+ShellPrintEx(\r
+  IN INT32                Col OPTIONAL,\r
+  IN INT32                Row OPTIONAL,\r
+  IN CONST CHAR16         *Format,\r
+  ...\r
+  ) \r
+{\r
+  VA_LIST           Marker;\r
+  VA_START (Marker, Format);\r
+  return (InternalShellPrintWorker(Col, Row, Format, Marker));\r
+}\r
+\r
+/**\r
+  Print at a specific location on the screen.\r
+\r
+  This function will move the cursor to a given screen location, print the specified string, \r
+  and return the cursor to the original locaiton.  \r
+  \r
+  If -1 is specified for either the Row or Col the current screen location for BOTH \r
+  will be used and the cursor's position will not be moved back to an original location.\r
+\r
+  if either Row or Col is out of range for the current console, then ASSERT\r
+  if Format is NULL, then ASSERT\r
+\r
+  In addition to the standard %-based flags as supported by UefiLib Print() this supports \r
+  the following additional flags:\r
+    %N       -   Set output attribute to normal\r
+    %H       -   Set output attribute to highlight\r
+    %E       -   Set output attribute to error\r
+    %B       -   Set output attribute to blue color\r
+    %V       -   Set output attribute to green color\r
+\r
+  Note: The background color is controlled by the shell command cls.\r
+\r
+  @param[in] Row                the row to print at\r
+  @param[in] Col                the column to print at\r
+  @param[in] HiiFormatStringId  the format string Id for getting from Hii\r
+  @param[in] HiiFormatHandle    the format string Handle for getting from Hii\r
+\r
+  @return the number of characters printed to the screen\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellPrintHiiEx(\r
+  IN INT32                Col OPTIONAL,\r
+  IN INT32                Row OPTIONAL,\r
+  IN CONST EFI_STRING_ID  HiiFormatStringId,\r
+  IN CONST EFI_HANDLE     HiiFormatHandle,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST           Marker;\r
+  CHAR16            *HiiFormatString;\r
+  UINTN             RetVal;\r
+\r
+  VA_START (Marker, HiiFormatHandle);\r
+  HiiFormatString = HiiGetString(HiiFormatHandle, HiiFormatStringId, NULL);\r
+  ASSERT(HiiFormatString != NULL);\r
+\r
+  RetVal = InternalShellPrintWorker(Col, Row, HiiFormatString, Marker);\r
+\r
+  FreePool(HiiFormatString);\r
+\r
+  return (RetVal);\r
+}\r
+\r
+/**\r
+  Function to determine if a given filename represents a file or a directory.\r
+\r
+  @param[in] DirName      Path to directory to test.\r
+\r
+  @retval EFI_SUCCESS     The Path represents a directory\r
+  @retval EFI_NOT_FOUND   The Path does not represent a directory\r
+  @return other           The path failed to open\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellIsDirectory(\r
+  IN CONST CHAR16 *DirName\r
+  )\r
+{\r
+  EFI_STATUS        Status;\r
+  EFI_FILE_HANDLE   Handle;\r
+\r
+  Handle = NULL;\r
+\r
+  Status = ShellOpenFileByName(DirName, &Handle, EFI_FILE_MODE_READ, 0);\r
+  if (EFI_ERROR(Status)) {\r
+    return (Status);\r
+  }\r
+\r
+  if (FileHandleIsDirectory(Handle) == EFI_SUCCESS) {\r
+    ShellCloseFile(&Handle);\r
+    return (EFI_SUCCESS);\r
+  }\r
+  ShellCloseFile(&Handle);\r
+  return (EFI_NOT_FOUND);\r
+}\r
+\r
+/**\r
+  Function to determine whether a string is decimal or hex representation of a number \r
+  and return the number converted from the string.\r
+\r
+  @param[in] String   String representation of a number\r
+\r
+  @retval all         the number\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellStrToUintn(\r
+  IN CONST CHAR16 *String\r
+  )\r
+{\r
+  CONST CHAR16  *Walker;\r
+  for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker = Walker + 1);\r
+  if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0){\r
+    return (StrHexToUintn(Walker));\r
+  }\r
+  return (StrDecimalToUintn(Walker));\r
+}\r
+\r
+/**\r
+  Safely append with automatic string resizing given length of Destination and\r
+  desired length of copy from Source.\r
+\r
+  append the first D characters of Source to the end of Destination, where D is\r
+  the lesser of Count and the StrLen() of Source. If appending those D characters\r
+  will fit within Destination (whose Size is given as CurrentSize) and\r
+  still leave room for a null terminator, then those characters are appended,\r
+  starting at the original terminating null of Destination, and a new terminating\r
+  null is appended.\r
+\r
+  If appending D characters onto Destination will result in a overflow of the size\r
+  given in CurrentSize the string will be grown such that the copy can be performed\r
+  and CurrentSize will be updated to the new size.\r
+\r
+  If Source is NULL, there is nothing to append, just return the current buffer in\r
+  Destination.\r
+\r
+  if Destination is NULL, then ASSERT()\r
+  if Destination's current length (including NULL terminator) is already more then\r
+  CurrentSize, then ASSERT()\r
+\r
+  @param[in,out] Destination   The String to append onto\r
+  @param[in,out] CurrentSize   on call the number of bytes in Destination.  On\r
+                                return possibly the new size (still in bytes).  if NULL\r
+                                then allocate whatever is needed.\r
+  @param[in]      Source        The String to append from\r
+  @param[in]      Count         Maximum number of characters to append.  if 0 then\r
+                                all are appended.\r
+\r
+  @return Destination           return the resultant string.\r
+**/\r
+CHAR16*\r
+EFIAPI\r
+StrnCatGrow (\r
+  IN OUT CHAR16           **Destination,\r
+  IN OUT UINTN            *CurrentSize,\r
+  IN     CONST CHAR16     *Source,\r
+  IN     UINTN            Count\r
+  )\r
+{\r
+  UINTN DestinationStartSize;\r
+  UINTN NewSize;\r
+\r
+  //\r
+  // ASSERTs\r
+  //\r
+  ASSERT(Destination != NULL);\r
+\r
+  //\r
+  // If there's nothing to do then just return Destination\r
+  //\r
+  if (Source == NULL) {\r
+    return (*Destination);\r
+  }\r
+\r
+  //\r
+  // allow for un-initialized pointers, based on size being 0\r
+  //\r
+  if (CurrentSize != NULL && *CurrentSize == 0) {\r
+    *Destination = NULL;\r
+  }\r
+\r
+  //\r
+  // allow for NULL pointers address as Destination\r
+  //\r
+  if (*Destination != NULL) {\r
+    ASSERT(CurrentSize != 0);\r
+    DestinationStartSize = StrSize(*Destination);\r
+    ASSERT(DestinationStartSize <= *CurrentSize);\r
+  } else {\r
+    DestinationStartSize = 0;\r
+//    ASSERT(*CurrentSize == 0);\r
+  }\r
+\r
+  //\r
+  // Append all of Source?\r
+  //\r
+  if (Count == 0) {\r
+    Count = StrLen(Source);\r
+  }\r
+\r
+  //\r
+  // Test and grow if required\r
+  //\r
+  if (CurrentSize != NULL) {\r
+    NewSize = *CurrentSize;\r
+    while (NewSize < (DestinationStartSize + (Count*sizeof(CHAR16)))) {\r
+      NewSize += 2 * Count * sizeof(CHAR16);\r
+    }\r
+    *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
+    *CurrentSize = NewSize;\r
+  } else {\r
+    *Destination = AllocateZeroPool((Count+1)*sizeof(CHAR16));\r
+  }\r
+\r
+  //\r
+  // Now use standard StrnCat on a big enough buffer\r
+  //\r
+  return StrnCat(*Destination, Source, Count);\r
+}\r