]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/Shell.c
ShellPkg: Fix ASCII and UNICODE file pipes.
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
index 87fd5e15edf87a4def0249193a5edf8f0658f6f3..40ae68d5a81f978976856de8c4b30f804aea62fa 100644 (file)
@@ -1,8 +1,8 @@
 /** @file\r
   This is THE shell (application)\r
 \r
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
-  Copyright (c) 2013, Hewlett-Packard Development Company, L.P.\r
+  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -101,30 +101,92 @@ TrimSpaces(
 }\r
 \r
 /**\r
-  Find a command line contains a split operation\r
+  Parse for the next instance of one string within another string. Can optionally make sure that \r
+  the string was not escaped (^ character) per the shell specification.\r
 \r
-  @param[in] CmdLine      The command line to parse.\r
-\r
-  @retval                 A pointer to the | character in CmdLine or NULL if not present.\r
+  @param[in] SourceString             The string to search within\r
+  @param[in] FindString               The string to look for\r
+  @param[in] CheckForEscapeCharacter  TRUE to skip escaped instances of FinfString, otherwise will return even escaped instances\r
 **/\r
-CONST CHAR16*\r
+CHAR16*\r
 EFIAPI\r
-FindSplit(\r
-  IN CONST CHAR16 *CmdLine\r
+FindNextInstance(\r
+  IN CONST CHAR16   *SourceString,\r
+  IN CONST CHAR16   *FindString,\r
+  IN CONST BOOLEAN  CheckForEscapeCharacter\r
   )\r
 {\r
-  CONST CHAR16 *TempSpot;\r
-  TempSpot = NULL;\r
-  if (StrStr(CmdLine, L"|") != NULL) {\r
-    for (TempSpot = CmdLine ; TempSpot != NULL && *TempSpot != CHAR_NULL ; TempSpot++) {\r
-      if (*TempSpot == L'^' && *(TempSpot+1) == L'|') {\r
-        TempSpot++;\r
-      } else if (*TempSpot == L'|') {\r
-        break;\r
+  CHAR16 *Temp;\r
+  if (SourceString == NULL) {\r
+    return (NULL);\r
+  }\r
+  Temp = StrStr(SourceString, FindString);\r
+\r
+  //\r
+  // If nothing found, or we don't care about escape characters\r
+  //\r
+  if (Temp == NULL || !CheckForEscapeCharacter) {\r
+    return (Temp);\r
+  }\r
+\r
+  //\r
+  // If we found an escaped character, try again on the remainder of the string\r
+  //\r
+  if ((Temp > (SourceString)) && *(Temp-1) == L'^') {\r
+    return FindNextInstance(Temp+1, FindString, CheckForEscapeCharacter);\r
+  }\r
+\r
+  //\r
+  // we found the right character\r
+  //\r
+  return (Temp);\r
+}\r
+\r
+/**\r
+  Check whether the string between a pair of % is a valid environment variable name.\r
+\r
+  @param[in] BeginPercent       pointer to the first percent.\r
+  @param[in] EndPercent          pointer to the last percent.\r
+\r
+  @retval TRUE                          is a valid environment variable name.\r
+  @retval FALSE                         is NOT a valid environment variable name.\r
+**/\r
+BOOLEAN\r
+IsValidEnvironmentVariableName(\r
+  IN CONST CHAR16     *BeginPercent,\r
+  IN CONST CHAR16     *EndPercent\r
+  )\r
+{\r
+  CONST CHAR16    *Walker;\r
+  \r
+  Walker = NULL;\r
+\r
+  ASSERT (BeginPercent != NULL);\r
+  ASSERT (EndPercent != NULL);\r
+  ASSERT (BeginPercent < EndPercent);\r
+  \r
+  if ((BeginPercent + 1) == EndPercent) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (Walker = BeginPercent + 1; Walker < EndPercent; Walker++) {\r
+    if (\r
+        (*Walker >= L'0' && *Walker <= L'9') ||\r
+        (*Walker >= L'A' && *Walker <= L'Z') ||\r
+        (*Walker >= L'a' && *Walker <= L'z') ||\r
+        (*Walker == L'_')\r
+      ) {\r
+      if (Walker == BeginPercent + 1 && (*Walker >= L'0' && *Walker <= L'9')) {\r
+        return FALSE;\r
+      } else {\r
+        continue;\r
       }\r
+    } else {\r
+      return FALSE;\r
     }\r
   }\r
-  return (TempSpot);\r
+\r
+  return TRUE;\r
 }\r
 \r
 /**\r
@@ -142,7 +204,39 @@ ContainsSplit(
   )\r
 {\r
   CONST CHAR16 *TempSpot;\r
-  TempSpot = FindSplit(CmdLine);\r
+  CONST CHAR16 *FirstQuote;\r
+  CONST CHAR16 *SecondQuote;\r
+\r
+  FirstQuote    = FindNextInstance (CmdLine, L"\"", TRUE);\r
+  SecondQuote   = NULL;\r
+  TempSpot      = FindFirstCharacter(CmdLine, L"|", L'^');\r
+\r
+  if (FirstQuote == NULL    || \r
+      TempSpot == NULL      || \r
+      TempSpot == CHAR_NULL || \r
+      FirstQuote > TempSpot\r
+      ) {\r
+    return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
+  }\r
+\r
+  while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) {\r
+    if (FirstQuote == NULL || FirstQuote > TempSpot) {\r
+      break;\r
+    }    \r
+    SecondQuote = FindNextInstance (FirstQuote + 1, L"\"", TRUE);\r
+    if (SecondQuote == NULL) {\r
+      break;\r
+    }\r
+    if (SecondQuote < TempSpot) {\r
+      FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);\r
+      continue;\r
+    } else {\r
+      FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);\r
+      TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^');\r
+      continue;\r
+    } \r
+  }\r
+  \r
   return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));\r
 }\r
 \r
@@ -151,7 +245,7 @@ ContainsSplit(
   feature's enabled state was not known when the shell initially launched.\r
 \r
   @retval EFI_SUCCESS           The feature is enabled.\r
-  @retval EFI_OUT_OF_RESOURCES  There is not enough mnemory available.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough memory available.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -244,9 +338,6 @@ UefiMain (
   UINTN                           Size;\r
   EFI_HANDLE                      ConInHandle;\r
   EFI_SIMPLE_TEXT_INPUT_PROTOCOL  *OldConIn;\r
-  UINTN                           ExitDataSize;\r
-  CHAR16                          *ExitData;\r
-  SHELL_STATUS                    ExitStatus;\r
 \r
   if (PcdGet8(PcdShellSupportLevel) > 3) {\r
     return (EFI_UNSUPPORTED);\r
@@ -300,12 +391,6 @@ UefiMain (
   // install our console logger.  This will keep a log of the output for back-browsing\r
   //\r
   Status = ConsoleLoggerInstall(ShellInfoObject.LogScreenCount, &ShellInfoObject.ConsoleInfo);\r
-  if(EFI_ERROR (Status)) {\r
-    ExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
-  } else {\r
-    ExitStatus = SHELL_SUCCESS;\r
-  }\r
-       \r
   if (!EFI_ERROR(Status)) {\r
     //\r
     // Enable the cursor to be visible\r
@@ -328,7 +413,8 @@ UefiMain (
         ///@todo Add our package into Framework HII\r
       }\r
       if (ShellInfoObject.HiiHandle == NULL) {\r
-        return (EFI_NOT_STARTED);\r
+        Status = EFI_NOT_STARTED;\r
+        goto FreeResources;\r
       }\r
     }\r
 \r
@@ -358,7 +444,10 @@ UefiMain (
     //\r
     // Check the command line\r
     //\r
-    Status = ProcessCommandLine();\r
+    Status = ProcessCommandLine ();\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeResources;\r
+    }\r
 \r
     //\r
     // If shell support level is >= 1 create the mappings and paths\r
@@ -415,7 +504,7 @@ UefiMain (
     // Display the mapping\r
     //\r
     if (PcdGet8(PcdShellSupportLevel) >= 2 && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap) {\r
-      Status = RunCommand(L"map", NULL);\r
+      Status = RunCommand(L"map");\r
       ASSERT_EFI_ERROR(Status);\r
     }\r
 \r
@@ -481,11 +570,7 @@ UefiMain (
         //\r
         // process the startup script or launch the called app.\r
         //\r
-        Status = DoStartupScript(\r
-                  ShellInfoObject.ImageDevPath,\r
-                  ShellInfoObject.FileDevPath,\r
-                  &ExitStatus\r
-                  );\r
+        Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
       }\r
 \r
       if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
@@ -505,6 +590,7 @@ UefiMain (
           // Reset page break back to default.\r
           //\r
           ShellInfoObject.PageBreakEnabled        = PcdGetBool(PcdShellPageBreakDefault);\r
+          ASSERT (ShellInfoObject.ConsoleInfo != NULL);\r
           ShellInfoObject.ConsoleInfo->Enabled    = TRUE;\r
           ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
 \r
@@ -518,7 +604,6 @@ UefiMain (
           //\r
           Status = DoShellPrompt();\r
         } while (!ShellCommandGetExit());\r
-        ExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
       }\r
       if (OldConIn != NULL && ConInHandle != NULL) {\r
         CloseSimpleTextInOnFile (gST->ConIn);\r
@@ -528,6 +613,7 @@ UefiMain (
     }\r
   }\r
 \r
+FreeResources:\r
   //\r
   // uninstall protocols / free memory / etc...\r
   //\r
@@ -589,35 +675,16 @@ UefiMain (
     DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);\r
   }\r
 \r
-  // If the command exited with an error, we pass this error out in the ExitData\r
-  // so that it can be retrieved by the EfiShellExecute function (which may\r
-  // start the shell with gBS->StartImage)\r
-  if (ExitStatus != SHELL_SUCCESS) {\r
-    // Allocate a buffer for exit data to pass to gBS->Exit().\r
-    // This buffer will contain the empty string immediately followed by\r
-    // the shell's exit status. (The empty string is required by the UEFI spec)\r
-    ExitDataSize = (sizeof (CHAR16) + sizeof (SHELL_STATUS));\r
-    ExitData = AllocatePool (ExitDataSize);\r
-    if (ExitData == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
-    ExitData[0] = '\0';\r
-    // Use CopyMem to avoid alignment faults\r
-    CopyMem ((ExitData + 1), &ExitStatus, sizeof (ExitStatus));\r
-\r
-    gBS->Exit (ImageHandle, EFI_ABORTED, ExitDataSize, ExitData);\r
-  } else {\r
-    return EFI_SUCCESS;\r
+  if (ShellCommandGetExit()) {\r
+    return ((EFI_STATUS)ShellCommandGetExitCode());\r
   }\r
-\r
-  ASSERT (FALSE);\r
-  return EFI_SUCCESS;\r
+  return (Status);\r
 }\r
 \r
 /**\r
   Sets all the alias' that were registered with the ShellCommandLib library.\r
 \r
-  @retval EFI_SUCCESS           all init commands were run sucessfully.\r
+  @retval EFI_SUCCESS           all init commands were run successfully.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -702,10 +769,10 @@ IsScriptOnlyCommand(
   loaded image protocol installed on it.  The FilePath will point to the device path\r
   for the file that was loaded.\r
 \r
-  @param[in, out] DevPath       On a sucessful return the device path to the loaded image.\r
-  @param[in, out] FilePath      On a sucessful return the device path to the file.\r
+  @param[in, out] DevPath       On a successful return the device path to the loaded image.\r
+  @param[in, out] FilePath      On a successful return the device path to the file.\r
 \r
-  @retval EFI_SUCCESS           The 2 device paths were sucessfully returned.\r
+  @retval EFI_SUCCESS           The 2 device paths were successfully returned.\r
   @retval other                 A error from gBS->HandleProtocol.\r
 \r
   @sa HandleProtocol\r
@@ -826,9 +893,13 @@ ProcessCommandLine(
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit         = FALSE;\r
   ShellInfoObject.ShellInitSettings.Delay = 5;\r
 \r
-  // Start LoopVar at 1 to ignore Argv[0] which is the name of this binary\r
-  // (probably "Shell.efi")\r
-  for (LoopVar = 1 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
+  //\r
+  // Start LoopVar at 0 to parse only optional arguments at Argv[0]\r
+  // and parse other parameters from Argv[1].  This is for use case that\r
+  // UEFI Shell boot option is created, and OptionalData is provided\r
+  // that starts with shell command-line options.\r
+  //\r
+  for (LoopVar = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
     CurrentArg = gEfiShellParametersProtocol->Argv[LoopVar];\r
     if (UnicodeCollation->StriColl (\r
                             UnicodeCollation,\r
@@ -908,7 +979,7 @@ ProcessCommandLine(
                                    ) == 0) {\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit         = TRUE;\r
     } else if (StrnCmp (L"-", CurrentArg, 1) == 0) {\r
-      // Unrecognised option\r
+      // Unrecognized option\r
       ShellPrintHiiEx(-1, -1, NULL,\r
         STRING_TOKEN (STR_GEN_PROBLEM),\r
         ShellInfoObject.HiiHandle,\r
@@ -916,7 +987,14 @@ ProcessCommandLine(
         );\r
       return EFI_INVALID_PARAMETER;\r
     } else {\r
-      ShellInfoObject.ShellInitSettings.FileName = AllocateZeroPool(StrSize(CurrentArg));\r
+      //\r
+      // First argument should be Shell.efi image name\r
+      //\r
+      if (LoopVar == 0) {\r
+        continue;\r
+      }\r
+\r
+      ShellInfoObject.ShellInitSettings.FileName = AllocateCopyPool(StrSize(CurrentArg), CurrentArg);\r
       if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
@@ -924,12 +1002,10 @@ ProcessCommandLine(
       // We found `file-name`.\r
       //\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
-\r
-      StrCpy (ShellInfoObject.ShellInitSettings.FileName, CurrentArg);\r
       LoopVar++;\r
 \r
       // Add `file-name-options`\r
-      for ( ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
+      for (Size = 0 ; LoopVar < gEfiShellParametersProtocol->Argc ; LoopVar++) {\r
         ASSERT((ShellInfoObject.ShellInitSettings.FileOptions == NULL && Size == 0) || (ShellInfoObject.ShellInitSettings.FileOptions != NULL));\r
         StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
                     &Size,\r
@@ -967,19 +1043,17 @@ ProcessCommandLine(
   @param ImagePath              the path to the image for shell.  first place to look for the startup script\r
   @param FilePath               the path to the file for shell.  second place to look for the startup script.\r
 \r
-  @param[out] ExitStatus      The exit code of the script. Ignored if NULL.\r
-\r
   @retval EFI_SUCCESS           the variable is initialized.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 DoStartupScript(\r
-  IN  EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
-  IN  EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
-  OUT SHELL_STATUS             *ExitStatus\r
+  IN EFI_DEVICE_PATH_PROTOCOL *ImagePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
   )\r
 {\r
   EFI_STATUS                    Status;\r
+  EFI_STATUS                    CalleeStatus;\r
   UINTN                         Delay;\r
   EFI_INPUT_KEY                 Key;\r
   SHELL_FILE_HANDLE             FileHandle;\r
@@ -1006,12 +1080,15 @@ DoStartupScript(
     if (FileStringPath == NULL) {\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
-    StrCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName);\r
+    StrCpyS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileName);\r
     if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
-      StrCat(FileStringPath, L" ");\r
-      StrCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions);\r
+      StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
+      StrnCatS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
+    }\r
+    Status = RunShellCommand(FileStringPath, &CalleeStatus);\r
+    if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit == TRUE) {\r
+      ShellCommandRegisterExit(gEfiShellProtocol->BatchIsActive(), (UINT64)CalleeStatus);\r
     }\r
-    Status = RunCommand(FileStringPath, ExitStatus);\r
     FreePool(FileStringPath);\r
     return (Status);\r
 \r
@@ -1088,30 +1165,18 @@ DoStartupScript(
   // If we got a file, run it\r
   //\r
   if (!EFI_ERROR(Status) && FileHandle != NULL) {\r
-    Status = RunScriptFile (\r
-              mStartupScript,\r
-              FileHandle,\r
-              L"",\r
-              ShellInfoObject.NewShellParametersProtocol,\r
-              ExitStatus\r
-              );\r
+    Status = RunScriptFile (mStartupScript, FileHandle, L"", ShellInfoObject.NewShellParametersProtocol);\r
     ShellInfoObject.NewEfiShellProtocol->CloseFile(FileHandle);\r
   } else {\r
     FileStringPath = ShellFindFilePath(mStartupScript);\r
     if (FileStringPath == NULL) {\r
       //\r
-      // we return success since we dont need to have a startup script\r
+      // we return success since we don't need to have a startup script\r
       //\r
       Status = EFI_SUCCESS;\r
       ASSERT(FileHandle == NULL);\r
     } else {\r
-      Status = RunScriptFile(\r
-                FileStringPath,\r
-                NULL,\r
-                L"",\r
-                ShellInfoObject.NewShellParametersProtocol,\r
-                ExitStatus\r
-                );\r
+      Status = RunScriptFile(FileStringPath, NULL, L"", ShellInfoObject.NewShellParametersProtocol);\r
       FreePool(FileStringPath);\r
     }\r
   }\r
@@ -1140,6 +1205,7 @@ DoShellPrompt (
   CONST CHAR16  *CurDir;\r
   UINTN         BufferSize;\r
   EFI_STATUS    Status;\r
+  LIST_ENTRY    OldBufferList;\r
 \r
   CurDir  = NULL;\r
 \r
@@ -1153,6 +1219,7 @@ DoShellPrompt (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  SaveBufferList(&OldBufferList);\r
   CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
 \r
   //\r
@@ -1176,12 +1243,13 @@ DoShellPrompt (
   //\r
   if (!EFI_ERROR (Status)) {\r
     CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
-    Status = RunCommand(CmdLine, NULL);\r
+    Status = RunCommand(CmdLine);\r
     }\r
 \r
   //\r
   // Done with this command\r
   //\r
+  RestoreBufferList(&OldBufferList);\r
   FreePool (CmdLine);\r
   return Status;\r
 }\r
@@ -1211,6 +1279,36 @@ AddBufferToFreeList(
   return (Buffer);\r
 }\r
 \r
+\r
+/**\r
+  Create a new buffer list and stores the old one to OldBufferList \r
+\r
+  @param OldBufferList   The temporary list head used to store the nodes in BufferToFreeList.\r
+**/\r
+VOID\r
+SaveBufferList (\r
+  OUT LIST_ENTRY     *OldBufferList\r
+  )\r
+{\r
+  CopyMem (OldBufferList, &ShellInfoObject.BufferToFreeList.Link, sizeof (LIST_ENTRY));\r
+  InitializeListHead (&ShellInfoObject.BufferToFreeList.Link);\r
+}\r
+\r
+/**\r
+  Restore previous nodes into BufferToFreeList .\r
+\r
+  @param OldBufferList   The temporary list head used to store the nodes in BufferToFreeList.\r
+**/\r
+VOID\r
+RestoreBufferList (\r
+  IN OUT LIST_ENTRY     *OldBufferList\r
+  )\r
+{\r
+  FreeBufferList (&ShellInfoObject.BufferToFreeList);\r
+  CopyMem (&ShellInfoObject.BufferToFreeList.Link, OldBufferList, sizeof (LIST_ENTRY));\r
+}\r
+\r
+\r
 /**\r
   Add a buffer to the Line History List\r
 \r
@@ -1223,14 +1321,40 @@ AddLineToCommandHistory(
   )\r
 {\r
   BUFFER_LIST *Node;\r
+  BUFFER_LIST *Walker;\r
+  UINT16       MaxHistoryCmdCount;\r
+  UINT16       Count;\r
+  \r
+  Count = 0;\r
+  MaxHistoryCmdCount = PcdGet16(PcdShellMaxHistoryCommandCount);\r
+  \r
+  if (MaxHistoryCmdCount == 0) {\r
+    return ;\r
+  }\r
+\r
 \r
   Node = AllocateZeroPool(sizeof(BUFFER_LIST));\r
   ASSERT(Node != NULL);\r
-  Node->Buffer = AllocateZeroPool(StrSize(Buffer));\r
+  Node->Buffer = AllocateCopyPool(StrSize(Buffer), Buffer);\r
   ASSERT(Node->Buffer != NULL);\r
-  StrCpy(Node->Buffer, Buffer);\r
 \r
-  InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
+  for ( Walker = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link)\r
+      ; !IsNull(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Walker->Link)\r
+      ; Walker = (BUFFER_LIST*)GetNextNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Walker->Link)\r
+   ){\r
+    Count++;\r
+  }\r
+  if (Count < MaxHistoryCmdCount){\r
+    InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
+  } else {\r
+    Walker = (BUFFER_LIST*)GetFirstNode(&ShellInfoObject.ViewingSettings.CommandHistory.Link);\r
+    RemoveEntryList(&Walker->Link);\r
+    if (Walker->Buffer != NULL) {\r
+      FreePool(Walker->Buffer);\r
+    }\r
+    FreePool(Walker);\r
+    InsertTailList(&ShellInfoObject.ViewingSettings.CommandHistory.Link, &Node->Link);\r
+  }\r
 }\r
 \r
 /**\r
@@ -1259,11 +1383,77 @@ ShellConvertAlias(
     return (EFI_SUCCESS);\r
   }\r
   FreePool(*CommandString);\r
-  *CommandString = AllocateZeroPool(StrSize(NewString));\r
+  *CommandString = AllocateCopyPool(StrSize(NewString), NewString);\r
   if (*CommandString == NULL) {\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
-  StrCpy(*CommandString, NewString);\r
+  return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+  This function will eliminate unreplaced (and therefore non-found) environment variables.\r
+\r
+  @param[in,out] CmdLine   The command line to update.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+StripUnreplacedEnvironmentVariables(\r
+  IN OUT CHAR16 *CmdLine\r
+  )\r
+{\r
+  CHAR16 *FirstPercent;\r
+  CHAR16 *FirstQuote;\r
+  CHAR16 *SecondPercent;\r
+  CHAR16 *SecondQuote;\r
+  CHAR16 *CurrentLocator;\r
+\r
+  for (CurrentLocator = CmdLine ; CurrentLocator != NULL ; ) {\r
+    FirstQuote = FindNextInstance(CurrentLocator, L"\"", TRUE);\r
+    FirstPercent = FindNextInstance(CurrentLocator, L"%", TRUE);\r
+    SecondPercent = FirstPercent!=NULL?FindNextInstance(FirstPercent+1, L"%", TRUE):NULL;\r
+    if (FirstPercent == NULL || SecondPercent == NULL) {\r
+      //\r
+      // If we ever don't have 2 % we are done.\r
+      //\r
+      break;\r
+    }\r
+\r
+    if (FirstQuote!= NULL && FirstQuote < FirstPercent) {\r
+      SecondQuote = FindNextInstance(FirstQuote+1, L"\"", TRUE);\r
+      //\r
+      // Quote is first found\r
+      //\r
+\r
+      if (SecondQuote < FirstPercent) {\r
+        //\r
+        // restart after the pair of "\r
+        //\r
+        CurrentLocator = SecondQuote + 1;\r
+      } else /* FirstPercent < SecondQuote */{\r
+        //\r
+        // Restart on the first percent\r
+        //\r
+        CurrentLocator = FirstPercent;\r
+      }\r
+      continue;\r
+    }\r
+    \r
+    if (FirstQuote == NULL || SecondPercent < FirstQuote) {\r
+      if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) {\r
+        //\r
+        // We need to remove from FirstPercent to SecondPercent\r
+        //\r
+        CopyMem(FirstPercent, SecondPercent + 1, StrSize(SecondPercent + 1));\r
+        //\r
+        // don't need to update the locator.  both % characters are gone.\r
+        //\r
+      } else {\r
+        CurrentLocator = SecondPercent + 1;\r
+      }\r
+      continue;\r
+    }\r
+    CurrentLocator = FirstQuote;\r
+  }\r
   return (EFI_SUCCESS);\r
 }\r
 \r
@@ -1275,7 +1465,7 @@ ShellConvertAlias(
 \r
   @param[in] OriginalCommandLine    The original command line\r
 \r
-  @retval NULL                      An error ocurred.\r
+  @retval NULL                      An error occurred.\r
   @return                           The new command line with no environment variables present.\r
 **/\r
 CHAR16*\r
@@ -1289,7 +1479,6 @@ ShellConvertVariables (
   CHAR16              *NewCommandLine1;\r
   CHAR16              *NewCommandLine2;\r
   CHAR16              *Temp;\r
-  CHAR16              *Temp2;\r
   UINTN               ItemSize;\r
   CHAR16              *ItemTemp;\r
   SCRIPT_FILE         *CurrentScriptFile;\r
@@ -1317,7 +1506,7 @@ ShellConvertVariables (
         ;  Temp = StrStr(Temp+1, AliasListNode->Alias)\r
        ){\r
         //\r
-        // we need a preceeding and if there is space no ^ preceeding (if no space ignore)\r
+        // we need a preceding and if there is space no ^ preceding (if no space ignore)\r
         //\r
         if ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2)) {\r
           NewSize += StrSize(AliasListNode->CommandString);\r
@@ -1338,7 +1527,7 @@ ShellConvertVariables (
       ;  Temp = StrStr(Temp+1, MasterEnvList)\r
      ){\r
       //\r
-      // we need a preceeding and following % and if there is space no ^ preceeding (if no space ignore)\r
+      // we need a preceding and following % and if there is space no ^ preceding (if no space ignore)\r
       //\r
       if (*(Temp-1) == L'%' && *(Temp+StrLen(MasterEnvList)) == L'%' &&\r
         ((((Temp-OriginalCommandLine)>2) && *(Temp-2) != L'^') || ((Temp-OriginalCommandLine)<=2))) {\r
@@ -1350,7 +1539,7 @@ ShellConvertVariables (
   //\r
   // now do the replacements...\r
   //\r
-  NewCommandLine1 = AllocateZeroPool(NewSize);\r
+  NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine);\r
   NewCommandLine2 = AllocateZeroPool(NewSize);\r
   ItemTemp        = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
   if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
@@ -1359,16 +1548,24 @@ ShellConvertVariables (
     SHELL_FREE_NON_NULL(ItemTemp);\r
     return (NULL);\r
   }\r
-  StrCpy(NewCommandLine1, OriginalCommandLine);\r
   for (MasterEnvList = EfiShellGetEnv(NULL)\r
-    ;  MasterEnvList != NULL && *MasterEnvList != CHAR_NULL //&& *(MasterEnvList+1) != CHAR_NULL\r
+    ;  MasterEnvList != NULL && *MasterEnvList != CHAR_NULL\r
     ;  MasterEnvList += StrLen(MasterEnvList) + 1\r
    ){\r
-    StrCpy(ItemTemp, L"%");\r
-    StrCat(ItemTemp, MasterEnvList);\r
-    StrCat(ItemTemp, L"%");\r
+    StrCpyS( ItemTemp, \r
+              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+              L"%"\r
+              );\r
+    StrCatS( ItemTemp, \r
+              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+              MasterEnvList\r
+              );\r
+    StrCatS( ItemTemp, \r
+              ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16)), \r
+              L"%"\r
+              );\r
     ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, ItemTemp, EfiShellGetEnv(MasterEnvList), TRUE, FALSE);\r
-    StrCpy(NewCommandLine1, NewCommandLine2);\r
+    StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
   }\r
   if (CurrentScriptFile != NULL) {\r
     for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
@@ -1376,52 +1573,20 @@ ShellConvertVariables (
       ;  AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
    ){\r
     ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);\r
-    StrCpy(NewCommandLine1, NewCommandLine2);\r
-    }\r
-\r
-    //\r
-    // Remove non-existant environment variables in scripts only\r
-    //\r
-    for (Temp = NewCommandLine1 ; Temp != NULL ; ) {\r
-      Temp = StrStr(Temp, L"%");\r
-      if (Temp == NULL) {\r
-        break;\r
-      }\r
-      while (*(Temp - 1) == L'^') {\r
-        Temp = StrStr(Temp + 1, L"%");\r
-        if (Temp == NULL) {\r
-          break;\r
-       }\r
-      }\r
-      if (Temp == NULL) {\r
-        break;\r
-      }\r
-      \r
-      Temp2 = StrStr(Temp + 1, L"%");\r
-      if (Temp2 == NULL) {\r
-        break;\r
-      }\r
-      while (*(Temp2 - 1) == L'^') {\r
-        Temp2 = StrStr(Temp2 + 1, L"%");\r
-        if (Temp2 == NULL) {\r
-          break;\r
-        }\r
-      }\r
-      if (Temp2 == NULL) {\r
-        break;\r
-      }\r
-      \r
-      Temp2++;\r
-      CopyMem(Temp, Temp2, StrSize(Temp2));\r
+    StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
     }\r
-\r
   }\r
 \r
+  //\r
+  // Remove non-existent environment variables\r
+  //\r
+  StripUnreplacedEnvironmentVariables(NewCommandLine1);\r
+\r
   //\r
   // Now cleanup any straggler intentionally ignored "%" characters\r
   //\r
   ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", L"%", TRUE, FALSE);\r
-  StrCpy(NewCommandLine1, NewCommandLine2);\r
+  StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
   \r
   FreePool(NewCommandLine2);\r
   FreePool(ItemTemp);\r
@@ -1436,9 +1601,6 @@ ShellConvertVariables (
   @param[in] StdIn          The pointer to the Standard input.\r
   @param[in] StdOut         The pointer to the Standard output.\r
 \r
-  @param[out] ExitStatus      The exit code of the last command in the pipeline.\r
-                              Ignored if NULL.\r
-\r
   @retval EFI_SUCCESS       The split command is executed successfully.\r
   @retval other             Some error occurs when executing the split command.\r
 **/\r
@@ -1447,8 +1609,7 @@ EFIAPI
 RunSplitCommand(\r
   IN CONST CHAR16             *CmdLine,\r
   IN       SHELL_FILE_HANDLE  *StdIn,\r
-  IN       SHELL_FILE_HANDLE  *StdOut,\r
-  OUT      SHELL_STATUS       *ExitStatus\r
+  IN       SHELL_FILE_HANDLE  *StdOut\r
   )\r
 {\r
   EFI_STATUS        Status;\r
@@ -1481,11 +1642,18 @@ RunSplitCommand(
     SHELL_FREE_NON_NULL(OurCommandLine);\r
     SHELL_FREE_NON_NULL(NextCommandLine);\r
     return (EFI_INVALID_PARAMETER);\r
-  } else if (NextCommandLine[0] != CHAR_NULL &&\r
-      NextCommandLine[0] == L'a' &&\r
-      NextCommandLine[1] == L' '\r
-     ){\r
+  } else if (NextCommandLine[0] == L'a' &&\r
+             (NextCommandLine[1] == L' ' || NextCommandLine[1] == CHAR_NULL)\r
+            ){\r
     CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0]));\r
+    while (NextCommandLine[0] == L' ') {\r
+      CopyMem(NextCommandLine, NextCommandLine+1, StrSize(NextCommandLine) - sizeof(NextCommandLine[0]));\r
+    }\r
+    if (NextCommandLine[0] == CHAR_NULL) {\r
+      SHELL_FREE_NON_NULL(OurCommandLine);\r
+      SHELL_FREE_NON_NULL(NextCommandLine);\r
+      return (EFI_INVALID_PARAMETER);\r
+    }\r
     Unicode = FALSE;\r
   } else {\r
     Unicode = TRUE;\r
@@ -1502,7 +1670,7 @@ RunSplitCommand(
   ASSERT(Split->SplitStdOut != NULL);\r
   InsertHeadList(&ShellInfoObject.SplitList.Link, &Split->Link);\r
 \r
-  Status = RunCommand(OurCommandLine, NULL);\r
+  Status = RunCommand(OurCommandLine);\r
 \r
   //\r
   // move the output from the first to the in to the second.\r
@@ -1517,7 +1685,7 @@ RunSplitCommand(
   ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);\r
 \r
   if (!EFI_ERROR(Status)) {\r
-    Status = RunCommand(NextCommandLine, ExitStatus);\r
+    Status = RunCommand(NextCommandLine);\r
   }\r
 \r
   //\r
@@ -1668,10 +1836,12 @@ GetOperationType(
   }\r
 \r
   //\r
-  // Test for file system change request.  anything ending with : and cant have spaces.\r
+  // Test for file system change request.  anything ending with first : and cant have spaces.\r
   //\r
   if (CmdName[(StrLen(CmdName)-1)] == L':') {\r
-    if (StrStr(CmdName, L" ") != NULL) {\r
+    if ( StrStr(CmdName, L" ") != NULL \r
+      || StrLen(StrStr(CmdName, L":")) > 1\r
+      ) {\r
       return (Unknown_Invalid);\r
     }\r
     return (File_Sys_Change);\r
@@ -1753,12 +1923,12 @@ IsValidSplit(
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
     TempWalker = (CHAR16*)Temp;\r
-    GetNextParameter(&TempWalker, &FirstParameter);\r
-\r
-    if (GetOperationType(FirstParameter) == Unknown_Invalid) {\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
-      SetLastError(SHELL_NOT_FOUND);\r
-      Status = EFI_NOT_FOUND;\r
+    if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine), TRUE))) {\r
+      if (GetOperationType(FirstParameter) == Unknown_Invalid) {\r
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+        SetLastError(SHELL_NOT_FOUND);\r
+        Status = EFI_NOT_FOUND;\r
+      }\r
     }\r
   }\r
 \r
@@ -1785,42 +1955,46 @@ VerifySplit(
   EFI_STATUS    Status;\r
 \r
   //\r
-  // Verify up to the pipe or end character\r
+  // If this was the only item, then get out\r
   //\r
-  Status = IsValidSplit(CmdLine);\r
-  if (EFI_ERROR(Status)) {\r
-    return (Status);\r
+  if (!ContainsSplit(CmdLine)) {\r
+    return (EFI_SUCCESS);\r
   }\r
 \r
   //\r
-  // If this was the only item, then get out\r
+  // Verify up to the pipe or end character\r
   //\r
-  if (!ContainsSplit(CmdLine)) {\r
-    return (EFI_SUCCESS);\r
+  Status = IsValidSplit(CmdLine);\r
+  if (EFI_ERROR(Status)) {\r
+    return (Status);\r
   }\r
 \r
   //\r
   // recurse to verify the next item\r
   //\r
-  TempSpot = FindSplit(CmdLine)+1;\r
+  TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1;\r
+  if (*TempSpot == L'a' && \r
+      (*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL)\r
+     ) {\r
+    // If it's an ASCII pipe '|a'\r
+    TempSpot += 1;\r
+  }\r
+  \r
   return (VerifySplit(TempSpot));\r
 }\r
 \r
 /**\r
   Process a split based operation.\r
 \r
-  @param[in] CmdLine      Pointer to the command line to process\r
-  @param[out] ExitStatus  The exit status of the command. Ignored if NULL.\r
-                          Invalid if this function returns an error.\r
+  @param[in] CmdLine    pointer to the command line to process\r
 \r
   @retval EFI_SUCCESS   The operation was successful\r
-  @return               an error occured.\r
+  @return               an error occurred.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 ProcessNewSplitCommandLine(\r
-  IN CONST CHAR16       *CmdLine,\r
-  OUT      SHELL_STATUS *ExitStatus\r
+  IN CONST CHAR16 *CmdLine\r
   )\r
 {\r
   SPLIT_LIST                *Split;\r
@@ -1841,14 +2015,9 @@ ProcessNewSplitCommandLine(
   }\r
 \r
   if (Split == NULL) {\r
-    Status = RunSplitCommand(CmdLine, NULL, NULL, ExitStatus);\r
+    Status = RunSplitCommand(CmdLine, NULL, NULL);\r
   } else {\r
-    Status = RunSplitCommand(\r
-              CmdLine,\r
-              Split->SplitStdIn,\r
-              Split->SplitStdOut,\r
-              ExitStatus\r
-              );\r
+    Status = RunSplitCommand(CmdLine, Split->SplitStdIn, Split->SplitStdOut);\r
   }\r
   if (EFI_ERROR(Status)) {\r
     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_INVALID_SPLIT), ShellInfoObject.HiiHandle, CmdLine);\r
@@ -1907,9 +2076,9 @@ DoHelpUpdate(
 {\r
   CHAR16 *CurrentParameter;\r
   CHAR16 *Walker;\r
-  CHAR16 *LastWalker;\r
   CHAR16 *NewCommandLine;\r
   EFI_STATUS Status;\r
+  UINTN  NewCmdLineSize;\r
 \r
   Status = EFI_SUCCESS;\r
 \r
@@ -1920,21 +2089,26 @@ DoHelpUpdate(
 \r
   Walker = *CmdLine;\r
   while(Walker != NULL && *Walker != CHAR_NULL) {\r
-    LastWalker = Walker;\r
-    GetNextParameter(&Walker, &CurrentParameter);\r
-    if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {\r
-      LastWalker[0] = L' ';\r
-      LastWalker[1] = L' ';\r
-      NewCommandLine = AllocateZeroPool(StrSize(L"help ") + StrSize(*CmdLine));\r
-      if (NewCommandLine == NULL) {\r
-        Status = EFI_OUT_OF_RESOURCES;\r
+    if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine), TRUE))) {\r
+      if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {\r
+        CurrentParameter[0] = L' ';\r
+        CurrentParameter[1] = L' ';\r
+        NewCmdLineSize = StrSize(L"help ") + StrSize(*CmdLine);\r
+        NewCommandLine = AllocateZeroPool(NewCmdLineSize);\r
+        if (NewCommandLine == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          break;\r
+        }\r
+\r
+        //\r
+        // We know the space is sufficient since we just calculated it.\r
+        //\r
+        StrnCpyS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), L"help ", 5);\r
+        StrnCatS(NewCommandLine, NewCmdLineSize/sizeof(CHAR16), *CmdLine, StrLen(*CmdLine));\r
+        SHELL_FREE_NON_NULL(*CmdLine);\r
+        *CmdLine = NewCommandLine;\r
         break;\r
       }\r
-      StrCpy(NewCommandLine, L"help ");\r
-      StrCat(NewCommandLine, *CmdLine);\r
-      SHELL_FREE_NON_NULL(*CmdLine);\r
-      *CmdLine = NewCommandLine;\r
-      break;\r
     }\r
   }\r
 \r
@@ -1973,7 +2147,7 @@ SetLastError(
 \r
   @retval EFI_SUCCESS           The operation was successful\r
   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
-  @return                       some other error occured\r
+  @return                       some other error occurred\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -1995,6 +2169,7 @@ ProcessCommandLineToFinal(
   if (EFI_ERROR(Status)) {\r
     return (Status);\r
   }\r
+  ASSERT (*CmdLine != NULL);\r
 \r
   TrimSpaces(CmdLine);\r
 \r
@@ -2017,13 +2192,12 @@ ProcessCommandLineToFinal(
 /**\r
   Run an internal shell command.\r
 \r
-  This API will upadate the shell's environment since these commands are libraries.\r
+  This API will update the shell's environment since these commands are libraries.\r
   \r
   @param[in] CmdLine          the command line to run.\r
   @param[in] FirstParameter   the first parameter on the command line\r
   @param[in] ParamProtocol    the shell parameters protocol pointer\r
-\r
-  @param[out] ExitStatus      The exit code of the command. Ignored if NULL.\r
+  @param[out] CommandStatus   the status from the command line.\r
 \r
   @retval EFI_SUCCESS     The command was completed.\r
   @retval EFI_ABORTED     The command's operation was aborted.\r
@@ -2034,7 +2208,7 @@ RunInternalCommand(
   IN CONST CHAR16                   *CmdLine,\r
   IN       CHAR16                   *FirstParameter,\r
   IN EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol,\r
-  OUT      SHELL_STATUS             *ExitStatus OPTIONAL\r
+  OUT EFI_STATUS                    *CommandStatus\r
 )\r
 {\r
   EFI_STATUS                Status;\r
@@ -2042,11 +2216,24 @@ RunInternalCommand(
   CHAR16                    **Argv;\r
   SHELL_STATUS              CommandReturnedStatus;\r
   BOOLEAN                   LastError;\r
+  CHAR16                    *Walker;\r
+  CHAR16                    *NewCmdLine;  \r
+\r
+  NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
+  if (NewCmdLine == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
+    if (*Walker == L'^' && *(Walker+1) == L'#') {\r
+      CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
+    }\r
+  }\r
 \r
   //\r
   // get the argc and argv updated for internal commands\r
   //\r
-  Status = UpdateArgcArgv(ParamProtocol, CmdLine, &Argv, &Argc);\r
+  Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, Internal_Command, &Argv, &Argc);\r
   if (!EFI_ERROR(Status)) {\r
     //\r
     // Run the internal command.\r
@@ -2054,6 +2241,14 @@ RunInternalCommand(
     Status = ShellCommandRunCommandHandler(FirstParameter, &CommandReturnedStatus, &LastError);\r
 \r
     if (!EFI_ERROR(Status)) {\r
+      if (CommandStatus != NULL) {\r
+        if (CommandReturnedStatus != SHELL_SUCCESS) {\r
+          *CommandStatus = (EFI_STATUS)(CommandReturnedStatus | MAX_BIT);\r
+        } else {\r
+          *CommandStatus = EFI_SUCCESS;\r
+        }\r
+      }\r
+\r
       //\r
       // Update last error status.\r
       // some commands do not update last error.\r
@@ -2061,9 +2256,6 @@ RunInternalCommand(
       if (LastError) {\r
         SetLastError(CommandReturnedStatus);\r
       }\r
-      if (ExitStatus != NULL) {\r
-        *ExitStatus = CommandReturnedStatus;\r
-      }\r
 \r
       //\r
       // Pass thru the exitcode from the app.\r
@@ -2088,13 +2280,13 @@ RunInternalCommand(
   }\r
 \r
   //\r
-  // This is guarenteed to be called after UpdateArgcArgv no matter what else happened.\r
+  // This is guaranteed to be called after UpdateArgcArgv no matter what else happened.\r
   // This is safe even if the update API failed.  In this case, it may be a no-op.\r
   //\r
   RestoreArgcArgv(ParamProtocol, &Argv, &Argc);\r
 \r
   //\r
-  // If a script is running and the command is not a scipt only command, then\r
+  // If a script is running and the command is not a script only command, then\r
   // change return value to success so the script won't halt (unless aborted).\r
   //\r
   // Script only commands have to be able halt the script since the script will\r
@@ -2107,6 +2299,7 @@ RunInternalCommand(
     Status = EFI_SUCCESS;\r
   }\r
 \r
+  FreePool (NewCmdLine);\r
   return (Status);\r
 }\r
 \r
@@ -2117,9 +2310,7 @@ RunInternalCommand(
   @param[in] CmdLine          the command line to run.\r
   @param[in] FirstParameter   the first parameter on the command line\r
   @param[in] ParamProtocol    the shell parameters protocol pointer\r
-\r
-  @param[out] ExitStatus      The exit code of the command or file.\r
-                              Ignored if NULL.\r
+  @param[out] CommandStatus   the status from the command line.\r
 \r
   @retval EFI_SUCCESS     The command was completed.\r
   @retval EFI_ABORTED     The command's operation was aborted.\r
@@ -2131,10 +2322,11 @@ RunCommandOrFile(
   IN CONST CHAR16                   *CmdLine,\r
   IN       CHAR16                   *FirstParameter,\r
   IN EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol,\r
-  OUT      SHELL_STATUS             *ExitStatus\r
+  OUT EFI_STATUS                    *CommandStatus\r
 )\r
 {\r
   EFI_STATUS                Status;\r
+  EFI_STATUS                StartStatus;\r
   CHAR16                    *CommandWithPath;\r
   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
   SHELL_STATUS              CalleeExitStatus;\r
@@ -2146,12 +2338,7 @@ RunCommandOrFile(
 \r
   switch (Type) {\r
     case   Internal_Command:\r
-      Status = RunInternalCommand(\r
-                CmdLine,\r
-                FirstParameter,\r
-                ParamProtocol,\r
-                &CalleeExitStatus\r
-                );\r
+      Status = RunInternalCommand(CmdLine, FirstParameter, ParamProtocol, CommandStatus);\r
       break;\r
     case   Script_File_Name:\r
     case   Efi_Application:\r
@@ -2186,13 +2373,7 @@ RunCommandOrFile(
       }\r
       switch (Type) {\r
         case   Script_File_Name:\r
-          Status = RunScriptFile (\r
-                    CommandWithPath,\r
-                    NULL,\r
-                    CmdLine,\r
-                    ParamProtocol,\r
-                    &CalleeExitStatus\r
-                    );\r
+          Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
           break;\r
         case   Efi_Application:\r
           //\r
@@ -2212,8 +2393,7 @@ RunCommandOrFile(
             DevPath,\r
             CmdLine,\r
             NULL,\r
-            NULL,\r
-            NULL\r
+            &StartStatus\r
            );\r
 \r
           SHELL_FREE_NON_NULL(DevPath);\r
@@ -2221,7 +2401,11 @@ RunCommandOrFile(
           if(EFI_ERROR (Status)) {\r
             CalleeExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
           } else {\r
-            CalleeExitStatus = SHELL_SUCCESS;\r
+            CalleeExitStatus = (SHELL_STATUS) StartStatus;\r
+          }\r
+\r
+          if (CommandStatus != NULL) {\r
+            *CommandStatus = CalleeExitStatus;\r
           }\r
 \r
           //\r
@@ -2246,10 +2430,6 @@ RunCommandOrFile(
 \r
   SHELL_FREE_NON_NULL(CommandWithPath);\r
 \r
-  if (ExitStatus != NULL) {\r
-    *ExitStatus = CalleeExitStatus;\r
-  }\r
-\r
   return (Status);\r
 }\r
 \r
@@ -2260,9 +2440,7 @@ RunCommandOrFile(
   @param[in] CmdLine          the command line to run.\r
   @param[in] FirstParameter   the first parameter on the command line.\r
   @param[in] ParamProtocol    the shell parameters protocol pointer\r
-\r
-  @param[out] ExitStatus      The exit code of the command or file.\r
-                              Ignored if NULL.\r
+  @param[out] CommandStatus   the status from the command line.\r
 \r
   @retval EFI_SUCCESS     The command was completed.\r
   @retval EFI_ABORTED     The command's operation was aborted.\r
@@ -2274,7 +2452,7 @@ SetupAndRunCommandOrFile(
   IN   CHAR16                         *CmdLine,\r
   IN   CHAR16                         *FirstParameter,\r
   IN   EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol,\r
-  OUT  SHELL_STATUS                   *ExitStatus\r
+  OUT EFI_STATUS                    *CommandStatus\r
 )\r
 {\r
   EFI_STATUS                Status;\r
@@ -2293,13 +2471,8 @@ SetupAndRunCommandOrFile(
   // Now run the command, script, or application\r
   //\r
   if (!EFI_ERROR(Status)) {\r
-    Status = RunCommandOrFile(\r
-              Type,\r
-              CmdLine,\r
-              FirstParameter,\r
-              ParamProtocol,\r
-              ExitStatus\r
-              );\r
+    TrimSpaces(&CmdLine);\r
+    Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol, CommandStatus);\r
   }\r
 \r
   //\r
@@ -2324,16 +2497,16 @@ SetupAndRunCommandOrFile(
   command or dispatch an external application.\r
 \r
   @param[in] CmdLine      The command line to parse.\r
-  @param[out] ExitStatus  The exit code of the command. Ignored if NULL.\r
+  @param[out] CommandStatus   The status from the command line.\r
 \r
   @retval EFI_SUCCESS     The command was completed.\r
   @retval EFI_ABORTED     The command's operation was aborted.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-RunCommand(\r
-  IN CONST CHAR16         *CmdLine,\r
-  OUT      SHELL_STATUS   *ExitStatus\r
+RunShellCommand(\r
+  IN CONST CHAR16   *CmdLine,\r
+  OUT EFI_STATUS    *CommandStatus\r
   )\r
 {\r
   EFI_STATUS                Status;\r
@@ -2357,6 +2530,24 @@ RunCommand(
 \r
   TrimSpaces(&CleanOriginal);\r
 \r
+  //\r
+  // NULL out comments (leveraged from RunScriptFileHandle() ).\r
+  // The # character on a line is used to denote that all characters on the same line\r
+  // and to the right of the # are to be ignored by the shell.\r
+  // Afterwards, again remove spaces, in case any were between the last command-parameter and '#'.\r
+  //\r
+  for (TempWalker = CleanOriginal; TempWalker != NULL && *TempWalker != CHAR_NULL; TempWalker++) {\r
+    if (*TempWalker == L'^') {\r
+      if (*(TempWalker + 1) == L'#') {\r
+        TempWalker++;\r
+      }\r
+    } else if (*TempWalker == L'#') {\r
+      *TempWalker = CHAR_NULL;\r
+    }\r
+  }\r
+\r
+  TrimSpaces(&CleanOriginal);\r
+\r
   //\r
   // Handle case that passed in command line is just 1 or more " " characters.\r
   //\r
@@ -2372,10 +2563,10 @@ RunCommand(
   }\r
 \r
   //\r
-  // We dont do normal processing with a split command line (output from one command input to another)\r
+  // We don't do normal processing with a split command line (output from one command input to another)\r
   //\r
   if (ContainsSplit(CleanOriginal)) {\r
-    Status = ProcessNewSplitCommandLine(CleanOriginal, ExitStatus);\r
+    Status = ProcessNewSplitCommandLine(CleanOriginal);\r
     SHELL_FREE_NON_NULL(CleanOriginal);\r
     return (Status);\r
   } \r
@@ -2389,33 +2580,30 @@ RunCommand(
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
   TempWalker = CleanOriginal;\r
-  GetNextParameter(&TempWalker, &FirstParameter);\r
-\r
-  //\r
-  // Depending on the first parameter we change the behavior\r
-  //\r
-  switch (Type = GetOperationType(FirstParameter)) {\r
-    case   File_Sys_Change:\r
-      Status = ChangeMappedDrive(CleanOriginal);\r
-      break;\r
-    case   Internal_Command:\r
-    case   Script_File_Name:\r
-    case   Efi_Application:\r
-      Status = SetupAndRunCommandOrFile(\r
-                Type,\r
-                CleanOriginal,\r
-                FirstParameter,\r
-                ShellInfoObject.NewShellParametersProtocol,\r
-                ExitStatus\r
-                );\r
-      break;\r
-    default:\r
-      //\r
-      // Whatever was typed, it was invalid.\r
-      //\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
-      SetLastError(SHELL_NOT_FOUND);\r
-      break;\r
+  if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal), TRUE))) {\r
+    //\r
+    // Depending on the first parameter we change the behavior\r
+    //\r
+    switch (Type = GetOperationType(FirstParameter)) {\r
+      case   File_Sys_Change:\r
+        Status = ChangeMappedDrive (FirstParameter);\r
+        break;\r
+      case   Internal_Command:\r
+      case   Script_File_Name:\r
+      case   Efi_Application:\r
+        Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, ShellInfoObject.NewShellParametersProtocol, CommandStatus);\r
+        break;\r
+      default:\r
+        //\r
+        // Whatever was typed, it was invalid.\r
+        //\r
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+        SetLastError(SHELL_NOT_FOUND);\r
+        break;\r
+    }\r
+  } else {\r
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+    SetLastError(SHELL_NOT_FOUND);\r
   }\r
  \r
   SHELL_FREE_NON_NULL(CleanOriginal);\r
@@ -2424,9 +2612,30 @@ RunCommand(
   return (Status);\r
 }\r
 \r
+/**\r
+  Function will process and run a command line.\r
+\r
+  This will determine if the command line represents an internal shell \r
+  command or dispatch an external application.\r
+\r
+  @param[in] CmdLine      The command line to parse.\r
+\r
+  @retval EFI_SUCCESS     The command was completed.\r
+  @retval EFI_ABORTED     The command's operation was aborted.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RunCommand(\r
+  IN CONST CHAR16   *CmdLine\r
+  )\r
+{\r
+  return (RunShellCommand(CmdLine, NULL));\r
+}\r
+\r
+\r
 STATIC CONST UINT16 InvalidChars[] = {L'*', L'?', L'<', L'>', L'\\', L'/', L'\"', 0x0001, 0x0002};\r
 /**\r
-  Function determins if the CommandName COULD be a valid command.  It does not determine whether\r
+  Function determines if the CommandName COULD be a valid command.  It does not determine whether\r
   this is a valid command.  It only checks for invalid characters.\r
 \r
   @param[in] CommandName    The name to check\r
@@ -2462,21 +2671,19 @@ IsValidCommandName(
   @param[in] Handle             The handle to the already opened file.\r
   @param[in] Name               The name of the script file.\r
 \r
-  @param[out] ExitStatus      The exit code of the script. Ignored if NULL.\r
-\r
-  @retval EFI_SUCCESS           the script completed sucessfully\r
+  @retval EFI_SUCCESS           the script completed successfully\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 RunScriptFileHandle (\r
-  IN  SHELL_FILE_HANDLE  Handle,\r
-  IN  CONST CHAR16       *Name,\r
-  OUT SHELL_STATUS       *ExitStatus\r
+  IN SHELL_FILE_HANDLE  Handle,\r
+  IN CONST CHAR16       *Name\r
   )\r
 {\r
   EFI_STATUS          Status;\r
   SCRIPT_FILE         *NewScriptFile;\r
   UINTN               LoopVar;\r
+  UINTN               PrintBuffSize;\r
   CHAR16              *CommandLine;\r
   CHAR16              *CommandLine2;\r
   CHAR16              *CommandLine3;\r
@@ -2487,13 +2694,12 @@ RunScriptFileHandle (
   CONST CHAR16        *CurDir;\r
   UINTN               LineCount;\r
   CHAR16              LeString[50];\r
-  SHELL_STATUS        CalleeExitStatus;\r
+  LIST_ENTRY          OldBufferList;\r
 \r
   ASSERT(!ShellCommandGetScriptExit());\r
-  \r
-  CalleeExitStatus = SHELL_SUCCESS;\r
 \r
   PreScriptEchoState = ShellCommandGetEchoState();\r
+  PrintBuffSize = PcdGet16(PcdShellPrintBufferSize);\r
 \r
   NewScriptFile = (SCRIPT_FILE*)AllocateZeroPool(sizeof(SCRIPT_FILE));\r
   if (NewScriptFile == NULL) {\r
@@ -2568,12 +2774,12 @@ RunScriptFileHandle (
   //\r
   // Now enumerate through the commands and run each one.\r
   //\r
-  CommandLine = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
+  CommandLine = AllocateZeroPool(PrintBuffSize);\r
   if (CommandLine == NULL) {\r
     DeleteScriptFileStruct(NewScriptFile);\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
-  CommandLine2 = AllocateZeroPool(PcdGet16(PcdShellPrintBufferSize));\r
+  CommandLine2 = AllocateZeroPool(PrintBuffSize);\r
   if (CommandLine2 == NULL) {\r
     FreePool(CommandLine);\r
     DeleteScriptFileStruct(NewScriptFile);\r
@@ -2585,15 +2791,23 @@ RunScriptFileHandle (
       ; // conditional increment in the body of the loop\r
   ){\r
     ASSERT(CommandLine2 != NULL);\r
-    StrCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl);\r
+    StrnCpyS( CommandLine2, \r
+              PrintBuffSize/sizeof(CHAR16), \r
+              NewScriptFile->CurrentCommand->Cl,\r
+              PrintBuffSize/sizeof(CHAR16) - 1\r
+              );\r
+\r
+    SaveBufferList(&OldBufferList);\r
 \r
     //\r
     // NULL out comments\r
     //\r
     for (CommandLine3 = CommandLine2 ; CommandLine3 != NULL && *CommandLine3 != CHAR_NULL ; CommandLine3++) {\r
       if (*CommandLine3 == L'^') {\r
-        if (*(CommandLine3+1) == L'#' || *(CommandLine3+1) == L':') {\r
+        if ( *(CommandLine3+1) == L':') {\r
           CopyMem(CommandLine3, CommandLine3+1, StrSize(CommandLine3) - sizeof(CommandLine3[0]));\r
+        } else if (*(CommandLine3+1) == L'#') {\r
+          CommandLine3++;\r
         }\r
       } else if (*CommandLine3 == L'#') {\r
         *CommandLine3 = CHAR_NULL;\r
@@ -2604,7 +2818,11 @@ RunScriptFileHandle (
       //\r
       // Due to variability in starting the find and replace action we need to have both buffers the same.\r
       //\r
-      StrCpy(CommandLine, CommandLine2);\r
+      StrnCpyS( CommandLine, \r
+                PrintBuffSize/sizeof(CHAR16), \r
+                CommandLine2,\r
+                PrintBuffSize/sizeof(CHAR16) - 1\r
+                );\r
 \r
       //\r
       // Remove the %0 to %9 from the command line (if we have some arguments)\r
@@ -2612,51 +2830,55 @@ RunScriptFileHandle (
       if (NewScriptFile->Argv != NULL) {\r
         switch (NewScriptFile->Argc) {\r
           default:\r
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%9", NewScriptFile->Argv[9], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 9:\r
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%8", NewScriptFile->Argv[8], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 8:\r
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%7", NewScriptFile->Argv[7], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 7:\r
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%6", NewScriptFile->Argv[6], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 6:\r
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%5", NewScriptFile->Argv[5], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 5:\r
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%4", NewScriptFile->Argv[4], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 4:\r
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%3", NewScriptFile->Argv[3], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 3:\r
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%2", NewScriptFile->Argv[2], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 2:\r
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%1", NewScriptFile->Argv[1], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
           case 1:\r
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);\r
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%0", NewScriptFile->Argv[0], FALSE, FALSE);\r
             ASSERT_EFI_ERROR(Status);\r
             break;\r
           case 0:\r
             break;\r
         }\r
       }\r
-      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%1", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%2", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%3", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%4", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%5", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%6", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%7", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PcdGet16 (PcdShellPrintBufferSize), L"%8", L"\"\"", FALSE, FALSE);\r
-      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PcdGet16 (PcdShellPrintBufferSize), L"%9", L"\"\"", FALSE, FALSE);\r
-\r
-      StrCpy(CommandLine2, CommandLine);\r
+      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%1", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%2", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%3", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%4", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%5", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%6", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%7", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, PrintBuffSize, L"%8", L"\"\"", FALSE, FALSE);\r
+      Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, PrintBuffSize, L"%9", L"\"\"", FALSE, FALSE);\r
+\r
+      StrnCpyS( CommandLine2, \r
+                PrintBuffSize/sizeof(CHAR16), \r
+                CommandLine,\r
+                PrintBuffSize/sizeof(CHAR16) - 1\r
+                );\r
 \r
       LastCommand = NewScriptFile->CurrentCommand;\r
 \r
@@ -2675,7 +2897,7 @@ RunScriptFileHandle (
             //\r
             PreCommandEchoState = ShellCommandGetEchoState();\r
             ShellCommandSetEchoState(FALSE);\r
-            Status = RunCommand(CommandLine3+1, NULL);\r
+            Status = RunCommand(CommandLine3+1);\r
 \r
             //\r
             // If command was "@echo -off" or "@echo -on" then don't restore echo state\r
@@ -2697,7 +2919,7 @@ RunScriptFileHandle (
               }\r
               ShellPrintEx(-1, -1, L"%s\r\n", CommandLine2);\r
             }\r
-            Status = RunCommand(CommandLine3, NULL);\r
+            Status = RunCommand(CommandLine3);\r
           }\r
         }\r
 \r
@@ -2705,24 +2927,25 @@ RunScriptFileHandle (
           //\r
           // ShellCommandGetExitCode() always returns a UINT64\r
           //\r
-          CalleeExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
-          UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", CalleeExitStatus);\r
+          UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellCommandGetExitCode());\r
           DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
           InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
 \r
           ShellCommandRegisterExit(FALSE, 0);\r
           Status = EFI_SUCCESS;\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
         if (ShellGetExecutionBreakFlag()) {\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
         if (EFI_ERROR(Status)) {\r
-          CalleeExitStatus = (SHELL_STATUS) Status;\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
         if (ShellCommandGetExit()) {\r
-          CalleeExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
+          RestoreBufferList(&OldBufferList);\r
           break;\r
         }\r
       }\r
@@ -2741,6 +2964,7 @@ RunScriptFileHandle (
         NewScriptFile->CurrentCommand->Reset = TRUE;\r
       }\r
     }\r
+    RestoreBufferList(&OldBufferList);\r
   }\r
 \r
 \r
@@ -2754,11 +2978,6 @@ RunScriptFileHandle (
   if (ShellCommandGetCurrentScriptFile()==NULL) {\r
     ShellCommandSetEchoState(PreScriptEchoState);\r
   }\r
-\r
-  if (ExitStatus != NULL) {\r
-    *ExitStatus = CalleeExitStatus;\r
-  }\r
-\r
   return (EFI_SUCCESS);\r
 }\r
 \r
@@ -2770,18 +2989,15 @@ RunScriptFileHandle (
   @param[in] CmdLine            the command line to run.\r
   @param[in] ParamProtocol      the shell parameters protocol pointer\r
 \r
-  @param[out] ExitStatus      The exit code of the script. Ignored if NULL.\r
-\r
-  @retval EFI_SUCCESS           the script completed sucessfully\r
+  @retval EFI_SUCCESS           the script completed successfully\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
 RunScriptFile (\r
-  IN  CONST CHAR16                   *ScriptPath,\r
-  IN  SHELL_FILE_HANDLE              Handle OPTIONAL,\r
-  IN  CONST CHAR16                   *CmdLine,\r
-  IN  EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol,\r
-  OUT SHELL_STATUS                   *ExitStatus\r
+  IN CONST CHAR16                   *ScriptPath,\r
+  IN SHELL_FILE_HANDLE              Handle OPTIONAL,\r
+  IN CONST CHAR16                   *CmdLine,\r
+  IN EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -2796,7 +3012,7 @@ RunScriptFile (
   //\r
   // get the argc and argv updated for scripts\r
   //\r
-  Status = UpdateArgcArgv(ParamProtocol, CmdLine, &Argv, &Argc);\r
+  Status = UpdateArgcArgv(ParamProtocol, CmdLine, Script_File_Name, &Argv, &Argc);\r
   if (!EFI_ERROR(Status)) {\r
 \r
     if (Handle == NULL) {\r
@@ -2808,7 +3024,7 @@ RunScriptFile (
         //\r
         // run it\r
         //\r
-        Status = RunScriptFileHandle(FileHandle, ScriptPath, ExitStatus);\r
+        Status = RunScriptFileHandle(FileHandle, ScriptPath);\r
 \r
         //\r
         // now close the file\r
@@ -2816,15 +3032,50 @@ RunScriptFile (
         ShellCloseFile(&FileHandle);\r
       }\r
     } else {\r
-      Status = RunScriptFileHandle(Handle, ScriptPath, ExitStatus);\r
+      Status = RunScriptFileHandle(Handle, ScriptPath);\r
     }\r
   }\r
 \r
   //\r
-  // This is guarenteed to be called after UpdateArgcArgv no matter what else happened.\r
+  // This is guaranteed to be called after UpdateArgcArgv no matter what else happened.\r
   // This is safe even if the update API failed.  In this case, it may be a no-op.\r
   //\r
   RestoreArgcArgv(ParamProtocol, &Argv, &Argc);\r
 \r
   return (Status);\r
 }\r
+\r
+/**\r
+  Return the pointer to the first occurrence of any character from a list of characters.\r
+\r
+  @param[in] String           the string to parse\r
+  @param[in] CharacterList    the list of character to look for\r
+  @param[in] EscapeCharacter  An escape character to skip\r
+\r
+  @return the location of the first character in the string\r
+  @retval CHAR_NULL no instance of any character in CharacterList was found in String\r
+**/\r
+CONST CHAR16*\r
+EFIAPI\r
+FindFirstCharacter(\r
+  IN CONST CHAR16 *String,\r
+  IN CONST CHAR16 *CharacterList,\r
+  IN CONST CHAR16 EscapeCharacter\r
+  )\r
+{\r
+  UINT32 WalkChar;\r
+  UINT32 WalkStr;\r
+\r
+  for (WalkStr = 0; WalkStr < StrLen(String); WalkStr++) {\r
+    if (String[WalkStr] == EscapeCharacter) {\r
+      WalkStr++;\r
+      continue;\r
+    }\r
+    for (WalkChar = 0; WalkChar < StrLen(CharacterList); WalkChar++) {\r
+      if (String[WalkStr] == CharacterList[WalkChar]) {\r
+        return (&String[WalkStr]);\r
+      }\r
+    }\r
+  }\r
+  return (String + StrLen(String));\r
+}\r