]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/Shell.c
ShellPkg/Application: Fix various typos
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
index 29c65b7f27eda34c5e0c558a27dab7004c3e28f7..a5563070972ed1aaba020f99ef5f26751b9ae53e 100644 (file)
@@ -1,15 +1,10 @@
 /** @file\r
   This is THE shell (application)\r
 \r
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>\r
-  (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.\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
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.<BR>\r
+  Copyright 2015-2018 Dell Technologies.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -33,6 +28,7 @@ SHELL_INFO ShellInfoObject = {
       0,\r
       0,\r
       0,\r
+      0,\r
       0\r
     }},\r
     0,\r
@@ -69,6 +65,9 @@ SHELL_INFO ShellInfoObject = {
 STATIC CONST CHAR16 mScriptExtension[]      = L".NSH";\r
 STATIC CONST CHAR16 mExecutableExtensions[] = L".NSH;.EFI";\r
 STATIC CONST CHAR16 mStartupScript[]        = L"startup.nsh";\r
+CONST CHAR16 mNoNestingEnvVarName[]         = L"nonesting";\r
+CONST CHAR16 mNoNestingTrue[]               = L"True";\r
+CONST CHAR16 mNoNestingFalse[]              = L"False";\r
 \r
 /**\r
   Cleans off leading and trailing spaces and tabs.\r
@@ -76,7 +75,6 @@ STATIC CONST CHAR16 mStartupScript[]        = L"startup.nsh";
   @param[in] String pointer to the string to trim them off.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 TrimSpaces(\r
   IN CHAR16 **String\r
   )\r
@@ -101,30 +99,91 @@ 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
+  @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
+CHAR16*\r
+FindNextInstance(\r
+  IN CONST CHAR16   *SourceString,\r
+  IN CONST CHAR16   *FindString,\r
+  IN CONST BOOLEAN  CheckForEscapeCharacter\r
+  )\r
+{\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
-  @retval                 A pointer to the | character in CmdLine or NULL if not present.\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
-CONST CHAR16*\r
-EFIAPI\r
-FindSplit(\r
-  IN CONST CHAR16 *CmdLine\r
+BOOLEAN\r
+IsValidEnvironmentVariableName(\r
+  IN CONST CHAR16     *BeginPercent,\r
+  IN CONST CHAR16     *EndPercent\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
+  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
@@ -136,25 +195,55 @@ FindSplit(
   @retval FALSE           CmdLine does not have a valid split.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 ContainsSplit(\r
   IN CONST CHAR16 *CmdLine\r
   )\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
 /**\r
-  Function to start monitoring for CTRL-S using SimpleTextInputEx.  This \r
+  Function to start monitoring for CTRL-S using SimpleTextInputEx.  This\r
   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
 InternalEfiShellStartCtrlSMonitor(\r
   VOID\r
   )\r
@@ -172,8 +261,8 @@ InternalEfiShellStartCtrlSMonitor(
     EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
   if (EFI_ERROR(Status)) {\r
     ShellPrintHiiEx(\r
-      -1, \r
-      -1, \r
+      -1,\r
+      -1,\r
       NULL,\r
       STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
       ShellInfoObject.HiiHandle);\r
@@ -190,7 +279,7 @@ InternalEfiShellStartCtrlSMonitor(
     &KeyData,\r
     NotificationFunction,\r
     &ShellInfoObject.CtrlSNotifyHandle1);\r
-  \r
+\r
   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
   if (!EFI_ERROR(Status)) {\r
     Status = SimpleEx->RegisterKeyNotify(\r
@@ -208,7 +297,7 @@ InternalEfiShellStartCtrlSMonitor(
       &KeyData,\r
       NotificationFunction,\r
       &ShellInfoObject.CtrlSNotifyHandle3);\r
-  }  \r
+  }\r
   KeyData.KeyState.KeyShiftState  = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
   if (!EFI_ERROR(Status)) {\r
     Status = SimpleEx->RegisterKeyNotify(\r
@@ -244,9 +333,7 @@ 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
+  SPLIT_LIST                      *Split;\r
 \r
   if (PcdGet8(PcdShellSupportLevel) > 3) {\r
     return (EFI_UNSUPPORTED);\r
@@ -300,12 +387,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
@@ -356,6 +437,8 @@ UefiMain (
     Status = CommandInit();\r
     ASSERT_EFI_ERROR(Status);\r
 \r
+    Status = ShellInitEnvVarList ();\r
+\r
     //\r
     // Check the command line\r
     //\r
@@ -371,6 +454,29 @@ UefiMain (
       Status = ShellCommandCreateInitialMappingsAndPaths();\r
     }\r
 \r
+    //\r
+    // Set the environment variable for nesting support\r
+    //\r
+    Size = 0;\r
+    TempString = NULL;\r
+    if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
+      //\r
+      // No change.  require nesting in Shell Protocol Execute()\r
+      //\r
+      StrnCatGrow(&TempString,\r
+                  &Size,\r
+                  L"False",\r
+                  0);\r
+    } else {\r
+      StrnCatGrow(&TempString,\r
+                  &Size,\r
+                  mNoNestingTrue,\r
+                  0);\r
+    }\r
+    Status = InternalEfiShellSetEnv(mNoNestingEnvVarName, TempString, TRUE);\r
+    SHELL_FREE_NON_NULL(TempString);\r
+    Size = 0;\r
+\r
     //\r
     // save the device path for the loaded image and the device path for the filepath (under loaded image)\r
     // These are where to look for the startup.nsh file\r
@@ -419,7 +525,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
@@ -485,11 +591,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
@@ -513,17 +615,11 @@ UefiMain (
           ShellInfoObject.ConsoleInfo->Enabled    = TRUE;\r
           ShellInfoObject.ConsoleInfo->RowCounter = 0;\r
 \r
-          //\r
-          // Reset the CTRL-C event (yes we ignore the return values)\r
-          //\r
-          Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
-\r
           //\r
           // Display Prompt\r
           //\r
           Status = DoShellPrompt();\r
         } while (!ShellCommandGetExit());\r
-        ExitStatus = (SHELL_STATUS) ShellCommandGetExitCode();\r
       }\r
       if (OldConIn != NULL && ConInHandle != NULL) {\r
         CloseSimpleTextInOnFile (gST->ConIn);\r
@@ -557,7 +653,7 @@ FreeResources:
     if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){\r
       InternalEfiShellSetEnv(L"cwd", NULL, TRUE);\r
     }\r
-    CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol);\r
+    CleanUpShellEnvironment (ShellInfoObject.NewEfiShellProtocol);\r
     DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;);\r
   }\r
 \r
@@ -566,7 +662,17 @@ FreeResources:
   }\r
 \r
   if (!IsListEmpty(&ShellInfoObject.SplitList.Link)){\r
-    ASSERT(FALSE); ///@todo finish this de-allocation.\r
+    ASSERT(FALSE); ///@todo finish this de-allocation (free SplitStdIn/Out when needed).\r
+\r
+    for ( Split = (SPLIT_LIST*)GetFirstNode (&ShellInfoObject.SplitList.Link)\r
+        ; !IsNull (&ShellInfoObject.SplitList.Link, &Split->Link)\r
+        ; Split = (SPLIT_LIST *)GetNextNode (&ShellInfoObject.SplitList.Link, &Split->Link)\r
+     ) {\r
+      RemoveEntryList (&Split->Link);\r
+      FreePool (Split);\r
+    }\r
+\r
+    DEBUG_CODE (InitializeListHead (&ShellInfoObject.SplitList.Link););\r
   }\r
 \r
   if (ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
@@ -595,43 +701,22 @@ FreeResources:
     DEBUG_CODE(ShellInfoObject.ConsoleInfo = NULL;);\r
   }\r
 \r
-  if (!EFI_ERROR (Status)) {\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
+  ShellFreeEnvVarList ();\r
 \r
-      ASSERT (FALSE);\r
-      return EFI_SUCCESS;\r
-    } else {\r
-      return EFI_SUCCESS;\r
-    }\r
-  } else {\r
-    return Status;\r
+  if (ShellCommandGetExit()) {\r
+    return ((EFI_STATUS)ShellCommandGetExitCode());\r
   }\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
 SetBuiltInAlias(\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS          Status;\r
@@ -669,7 +754,6 @@ SetBuiltInAlias(
   @retval FALSE             The 2 command names are not the same.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 IsCommand(\r
   IN CONST CHAR16 *Command1,\r
   IN CONST CHAR16 *Command2\r
@@ -690,7 +774,6 @@ IsCommand(
   @retval FALSE             The command is not a script only command.\r
 **/\r
 BOOLEAN\r
-EFIAPI\r
 IsScriptOnlyCommand(\r
   IN CONST CHAR16 *CommandName\r
   )\r
@@ -712,16 +795,15 @@ 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
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 GetDevicePathsForImageAndFile (\r
   IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPath,\r
   IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath\r
@@ -797,7 +879,6 @@ GetDevicePathsForImageAndFile (
   @retval EFI_SUCCESS           The variable is initialized.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ProcessCommandLine(\r
   VOID\r
   )\r
@@ -816,12 +897,19 @@ ProcessCommandLine(
   // like a shell option (which is assumed to be `file-name`).\r
 \r
   Status = gBS->LocateProtocol (\r
-                  &gEfiUnicodeCollationProtocolGuid,\r
+                  &gEfiUnicodeCollation2ProtocolGuid,\r
                   NULL,\r
                   (VOID **) &UnicodeCollation\r
                   );\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    Status = gBS->LocateProtocol (\r
+                    &gEfiUnicodeCollationProtocolGuid,\r
+                    NULL,\r
+                    (VOID **) &UnicodeCollation\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   // Set default options\r
@@ -834,6 +922,7 @@ ProcessCommandLine(
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion    = FALSE;\r
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay        = FALSE;\r
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit         = FALSE;\r
+  ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest       = FALSE;\r
   ShellInfoObject.ShellInitSettings.Delay = 5;\r
 \r
   //\r
@@ -893,6 +982,13 @@ ProcessCommandLine(
                                  ) == 0) {\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion    = TRUE;\r
     }\r
+    else if (UnicodeCollation->StriColl (\r
+                                 UnicodeCollation,\r
+                                 L"-nonest",\r
+                                 CurrentArg\r
+                                 ) == 0) {\r
+      ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest       = TRUE;\r
+    }\r
     else if (UnicodeCollation->StriColl (\r
                                  UnicodeCollation,\r
                                  L"-delay",\r
@@ -900,7 +996,11 @@ ProcessCommandLine(
                                  ) == 0) {\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay        = TRUE;\r
       // Check for optional delay value following "-delay"\r
-      DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1];\r
+      if ((LoopVar + 1) >= gEfiShellParametersProtocol->Argc) {\r
+        DelayValueStr = NULL;\r
+      } else {\r
+        DelayValueStr = gEfiShellParametersProtocol->Argv[LoopVar + 1];\r
+      }\r
       if (DelayValueStr != NULL){\r
         if (*DelayValueStr == L':') {\r
           DelayValueStr++;\r
@@ -917,12 +1017,12 @@ ProcessCommandLine(
       }\r
     } else if (UnicodeCollation->StriColl (\r
                                    UnicodeCollation,\r
-                                   L"-_exit",\r
+                                   L"-exit",\r
                                    CurrentArg\r
                                    ) == 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
@@ -937,11 +1037,31 @@ ProcessCommandLine(
         continue;\r
       }\r
 \r
-      ShellInfoObject.ShellInitSettings.FileName = AllocateCopyPool(StrSize(CurrentArg), CurrentArg);\r
+      ShellInfoObject.ShellInitSettings.FileName = NULL;\r
+      Size = 0;\r
+      //\r
+      // If first argument contains a space, then add double quotes before the argument\r
+      //\r
+      if (StrStr (CurrentArg, L" ") != NULL) {\r
+        StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, L"\"", 0);\r
+        if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
+          return (EFI_OUT_OF_RESOURCES);\r
+        }\r
+      }\r
+      StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, CurrentArg, 0);\r
       if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
       //\r
+      // If first argument contains a space, then add double quotes after the argument\r
+      //\r
+      if (StrStr (CurrentArg, L" ") != NULL) {\r
+        StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileName, &Size, L"\"", 0);\r
+        if (ShellInfoObject.ShellInitSettings.FileName == NULL) {\r
+          return (EFI_OUT_OF_RESOURCES);\r
+        }\r
+      }\r
+      //\r
       // We found `file-name`.\r
       //\r
       ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoStartup = 1;\r
@@ -950,13 +1070,28 @@ ProcessCommandLine(
       // Add `file-name-options`\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
-                    L" ",\r
-                    0);\r
-        if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
-          SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
-          return (EFI_OUT_OF_RESOURCES);\r
+        //\r
+        // Add a space between arguments\r
+        //\r
+        if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
+          StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions, &Size, L" ", 0);\r
+          if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+            SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+            return (EFI_OUT_OF_RESOURCES);\r
+          }\r
+        }\r
+        //\r
+        // If an argument contains a space, then add double quotes before the argument\r
+        //\r
+        if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L" ") != NULL) {\r
+          StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
+                      &Size,\r
+                      L"\"",\r
+                      0);\r
+          if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+            SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+            return (EFI_OUT_OF_RESOURCES);\r
+          }\r
         }\r
         StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
                     &Size,\r
@@ -966,6 +1101,19 @@ ProcessCommandLine(
           SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
           return (EFI_OUT_OF_RESOURCES);\r
         }\r
+        //\r
+        // If an argument contains a space, then add double quotes after the argument\r
+        //\r
+        if (StrStr (gEfiShellParametersProtocol->Argv[LoopVar], L" ") != NULL) {\r
+          StrnCatGrow(&ShellInfoObject.ShellInitSettings.FileOptions,\r
+                      &Size,\r
+                      L"\"",\r
+                      0);\r
+          if (ShellInfoObject.ShellInitSettings.FileOptions == NULL) {\r
+            SHELL_FREE_NON_NULL(ShellInfoObject.ShellInitSettings.FileName);\r
+            return (EFI_OUT_OF_RESOURCES);\r
+          }\r
+        }\r
       }\r
     }\r
   }\r
@@ -978,6 +1126,66 @@ ProcessCommandLine(
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Function try to find location of the Startup.nsh file.\r
+\r
+  The buffer is callee allocated and should be freed by the caller.\r
+\r
+  @param    ImageDevicePath       The path to the image for shell.  first place to look for the startup script\r
+  @param    FileDevicePath        The path to the file for shell.  second place to look for the startup script.\r
+\r
+  @retval   NULL                  No Startup.nsh file was found.\r
+  @return   !=NULL                Pointer to NULL-terminated path.\r
+**/\r
+CHAR16 *\r
+LocateStartupScript (\r
+  IN EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,\r
+  IN EFI_DEVICE_PATH_PROTOCOL *FileDevicePath\r
+  )\r
+{\r
+  CHAR16          *StartupScriptPath;\r
+  CHAR16          *TempSpot;\r
+  CONST CHAR16    *MapName;\r
+  UINTN           Size;\r
+\r
+  StartupScriptPath = NULL;\r
+  Size              = 0;\r
+\r
+  //\r
+  // Try to find 'Startup.nsh' in the directory where the shell itself was launched.\r
+  //\r
+  MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath (&ImageDevicePath);\r
+  if (MapName != NULL) {\r
+    StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, MapName, 0);\r
+    if (StartupScriptPath == NULL) {\r
+      //\r
+      // Do not locate the startup script in sys path when out of resource.\r
+      //\r
+      return NULL;\r
+    }\r
+    TempSpot = StrStr (StartupScriptPath, L";");\r
+    if (TempSpot != NULL) {\r
+      *TempSpot = CHAR_NULL;\r
+    }\r
+\r
+    InternalEfiShellSetEnv(L"homefilesystem", StartupScriptPath, TRUE);\r
+\r
+    StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, ((FILEPATH_DEVICE_PATH *)FileDevicePath)->PathName, 0);\r
+    PathRemoveLastItem (StartupScriptPath);\r
+    StartupScriptPath = StrnCatGrow (&StartupScriptPath, &Size, mStartupScript, 0);\r
+  }\r
+\r
+  //\r
+  // Try to find 'Startup.nsh' in the execution path defined by the environment variable PATH.\r
+  //\r
+  if ((StartupScriptPath == NULL) || EFI_ERROR (ShellIsFile (StartupScriptPath))) {\r
+    SHELL_FREE_NON_NULL (StartupScriptPath);\r
+    StartupScriptPath = ShellFindFilePath (mStartupScript);\r
+  }\r
+\r
+  return StartupScriptPath;\r
+}\r
+\r
 /**\r
   Handles all interaction with the default startup script.\r
 \r
@@ -986,32 +1194,24 @@ 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
-  EFI_DEVICE_PATH_PROTOCOL      *NewPath;\r
-  EFI_DEVICE_PATH_PROTOCOL      *NamePath;\r
   CHAR16                        *FileStringPath;\r
-  CHAR16                        *TempSpot;\r
+  CHAR16                        *FullFileStringPath;\r
   UINTN                         NewSize;\r
-  CONST CHAR16                  *MapName;\r
 \r
   Key.UnicodeChar = CHAR_NULL;\r
   Key.ScanCode    = 0;\r
-  FileHandle      = NULL;\r
 \r
   if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Startup && ShellInfoObject.ShellInitSettings.FileName != NULL) {\r
     //\r
@@ -1025,12 +1225,15 @@ DoStartupScript(
     if (FileStringPath == NULL) {\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
-    StrnCpy(FileStringPath, ShellInfoObject.ShellInitSettings.FileName, NewSize/sizeof(CHAR16) -1);\r
+    StrCpyS(FileStringPath, NewSize/sizeof(CHAR16), ShellInfoObject.ShellInitSettings.FileName);\r
     if (ShellInfoObject.ShellInitSettings.FileOptions != NULL) {\r
-      StrnCat(FileStringPath, L" ", NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\r
-      StrnCat(FileStringPath, ShellInfoObject.ShellInitSettings.FileOptions, NewSize/sizeof(CHAR16) - StrLen(FileStringPath) -1);\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
@@ -1070,72 +1273,23 @@ DoStartupScript(
     return (EFI_SUCCESS);\r
   }\r
 \r
-  //\r
-  // Try the first location (must be file system)\r
-  //\r
-  MapName = ShellInfoObject.NewEfiShellProtocol->GetMapFromDevicePath(&ImagePath);\r
-  if (MapName != NULL) {\r
-    FileStringPath = NULL;\r
-    NewSize = 0;\r
-    FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, MapName, 0);\r
-    if (FileStringPath == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
+  FileStringPath = LocateStartupScript (ImagePath, FilePath);\r
+  if (FileStringPath != NULL) {\r
+    FullFileStringPath = FullyQualifyPath(FileStringPath);\r
+    if (FullFileStringPath == NULL) {\r
+      Status = RunScriptFile (FileStringPath, NULL, FileStringPath, ShellInfoObject.NewShellParametersProtocol);\r
     } else {\r
-      TempSpot = StrStr(FileStringPath, L";");\r
-      if (TempSpot != NULL) {\r
-        *TempSpot = CHAR_NULL;\r
-      }\r
-      FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, ((FILEPATH_DEVICE_PATH*)FilePath)->PathName, 0);\r
-      PathRemoveLastItem(FileStringPath);\r
-      FileStringPath = StrnCatGrow(&FileStringPath, &NewSize, mStartupScript, 0);\r
-      Status = ShellInfoObject.NewEfiShellProtocol->OpenFileByName(FileStringPath, &FileHandle, EFI_FILE_MODE_READ);\r
-      FreePool(FileStringPath);\r
+      Status = RunScriptFile (FullFileStringPath, NULL, FullFileStringPath, ShellInfoObject.NewShellParametersProtocol);\r
+      FreePool(FullFileStringPath);\r
     }\r
-  }\r
-  if (EFI_ERROR(Status)) {\r
-    NamePath = FileDevicePath (NULL, mStartupScript);\r
-    NewPath = AppendDevicePathNode (ImagePath, NamePath);\r
-    FreePool(NamePath);\r
-\r
+    FreePool (FileStringPath);\r
+  } else {\r
     //\r
-    // Try the location\r
+    // we return success since startup script is not mandatory.\r
     //\r
-    Status = InternalOpenFileDevicePath(NewPath, &FileHandle, EFI_FILE_MODE_READ, 0);\r
-    FreePool(NewPath);\r
-  }\r
-  //\r
-  // 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
-    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
-      //\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
-      FreePool(FileStringPath);\r
-    }\r
+    Status = EFI_SUCCESS;\r
   }\r
 \r
-\r
   return (Status);\r
 }\r
 \r
@@ -1148,7 +1302,6 @@ DoStartupScript(
   @retval RETURN_ABORTED\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 DoShellPrompt (\r
   VOID\r
   )\r
@@ -1159,6 +1312,7 @@ DoShellPrompt (
   CONST CHAR16  *CurDir;\r
   UINTN         BufferSize;\r
   EFI_STATUS    Status;\r
+  LIST_ENTRY    OldBufferList;\r
 \r
   CurDir  = NULL;\r
 \r
@@ -1172,6 +1326,7 @@ DoShellPrompt (
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
+  SaveBufferList(&OldBufferList);\r
   CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
 \r
   //\r
@@ -1194,13 +1349,19 @@ DoShellPrompt (
   // Null terminate the string and parse it\r
   //\r
   if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Reset the CTRL-C event just before running the command (yes we ignore the return values)\r
+    //\r
+    Status = gBS->CheckEvent (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak);\r
+\r
     CmdLine[BufferSize / sizeof (CHAR16)] = CHAR_NULL;\r
-    Status = RunCommand(CmdLine, NULL);\r
-    }\r
+    Status = RunCommand(CmdLine);\r
+  }\r
 \r
   //\r
   // Done with this command\r
   //\r
+  RestoreBufferList(&OldBufferList);\r
   FreePool (CmdLine);\r
   return Status;\r
 }\r
@@ -1212,8 +1373,7 @@ DoShellPrompt (
   @param Buffer   Something to pass to FreePool when the shell is exiting.\r
 **/\r
 VOID*\r
-EFIAPI\r
-AddBufferToFreeList(\r
+AddBufferToFreeList (\r
   VOID *Buffer\r
   )\r
 {\r
@@ -1223,32 +1383,97 @@ AddBufferToFreeList(
     return (NULL);\r
   }\r
 \r
-  BufferListEntry = AllocateZeroPool(sizeof(BUFFER_LIST));\r
-  ASSERT(BufferListEntry != NULL);\r
+  BufferListEntry = AllocateZeroPool (sizeof (BUFFER_LIST));\r
+  if (BufferListEntry == NULL) {\r
+    return NULL;\r
+  }\r
+\r
   BufferListEntry->Buffer = Buffer;\r
-  InsertTailList(&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);\r
+  InsertTailList (&ShellInfoObject.BufferToFreeList.Link, &BufferListEntry->Link);\r
   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
   @param Buffer     The line buffer to add.\r
 **/\r
 VOID\r
-EFIAPI\r
 AddLineToCommandHistory(\r
   IN CONST CHAR16 *Buffer\r
   )\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 = AllocateCopyPool(StrSize(Buffer), Buffer);\r
-  ASSERT(Node->Buffer != NULL);\r
+  if (Node == NULL) {\r
+    return;\r
+  }\r
+\r
+  Node->Buffer = AllocateCopyPool (StrSize (Buffer), Buffer);\r
+  if (Node->Buffer == NULL) {\r
+    FreePool (Node);\r
+    return;\r
+  }\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
@@ -1265,7 +1490,6 @@ AddLineToCommandHistory(
   @retval EFI_OUT_OF_RESOURCES    A memory allocation failed.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ShellConvertAlias(\r
   IN OUT CHAR16 **CommandString\r
   )\r
@@ -1284,55 +1508,12 @@ ShellConvertAlias(
   return (EFI_SUCCESS);\r
 }\r
 \r
-/**\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] 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
-CHAR16*\r
-EFIAPI\r
-FindNextInstance(\r
-  IN CONST CHAR16   *SourceString,\r
-  IN CONST CHAR16   *FindString,\r
-  IN CONST BOOLEAN  CheckForEscapeCharacter\r
-  )\r
-{\r
-  CHAR16 *Temp;\r
-  if (SourceString == NULL) {\r
-    return (NULL);\r
-  }\r
-  Temp = StrStr(SourceString, FindString);\r
-\r
-  //\r
-  // If nothing found, or we dont 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
   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
@@ -1349,13 +1530,13 @@ StripUnreplacedEnvironmentVariables(
     SecondPercent = FirstPercent!=NULL?FindNextInstance(FirstPercent+1, L"%", TRUE):NULL;\r
     if (FirstPercent == NULL || SecondPercent == NULL) {\r
       //\r
-      // If we ever dont have 2 % we are done.\r
+      // If we ever don't have 2 % we are done.\r
       //\r
       break;\r
     }\r
 \r
-    if (FirstQuote < FirstPercent) {\r
-      SecondQuote = FirstQuote!= NULL?FindNextInstance(FirstQuote+1, L"\"", TRUE):NULL;\r
+    if (FirstQuote!= NULL && FirstQuote < FirstPercent) {\r
+      SecondQuote = FindNextInstance(FirstQuote+1, L"\"", TRUE);\r
       //\r
       // Quote is first found\r
       //\r
@@ -1373,19 +1554,21 @@ StripUnreplacedEnvironmentVariables(
       }\r
       continue;\r
     }\r
-    ASSERT(FirstPercent < FirstQuote);\r
-    if (SecondPercent < FirstQuote) {\r
-      FirstPercent[0] = L'\"';\r
-      SecondPercent[0] = L'\"';\r
 \r
-      //\r
-      // We need to remove from FirstPercent to SecondPercent\r
-      //\r
-      CopyMem(FirstPercent + 1, SecondPercent, StrSize(SecondPercent));\r
-      CurrentLocator = FirstPercent + 2;\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
-    ASSERT(FirstQuote < SecondPercent);\r
     CurrentLocator = FirstQuote;\r
   }\r
   return (EFI_SUCCESS);\r
@@ -1399,11 +1582,10 @@ StripUnreplacedEnvironmentVariables(
 \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
-EFIAPI\r
 ShellConvertVariables (\r
   IN CONST CHAR16 *OriginalCommandLine\r
   )\r
@@ -1440,7 +1622,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
@@ -1461,7 +1643,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
@@ -1473,7 +1655,7 @@ ShellConvertVariables (
   //\r
   // now do the replacements...\r
   //\r
-  NewCommandLine1 = AllocateCopyPool(NewSize, OriginalCommandLine);\r
+  NewCommandLine1 = AllocateZeroPool (NewSize);\r
   NewCommandLine2 = AllocateZeroPool(NewSize);\r
   ItemTemp        = AllocateZeroPool(ItemSize+(2*sizeof(CHAR16)));\r
   if (NewCommandLine1 == NULL || NewCommandLine2 == NULL || ItemTemp == NULL) {\r
@@ -1482,15 +1664,26 @@ ShellConvertVariables (
     SHELL_FREE_NON_NULL(ItemTemp);\r
     return (NULL);\r
   }\r
+  CopyMem (NewCommandLine1, OriginalCommandLine, StrSize (OriginalCommandLine));\r
+\r
   for (MasterEnvList = EfiShellGetEnv(NULL)\r
     ;  MasterEnvList != NULL && *MasterEnvList != CHAR_NULL\r
     ;  MasterEnvList += StrLen(MasterEnvList) + 1\r
    ){\r
-    StrnCpy(ItemTemp, L"%", ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1);\r
-    StrnCat(ItemTemp, MasterEnvList, ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1 - StrLen(ItemTemp));\r
-    StrnCat(ItemTemp, L"%", ((ItemSize+(2*sizeof(CHAR16)))/sizeof(CHAR16))-1 - StrLen(ItemTemp));\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
-    StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
+    StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
   }\r
   if (CurrentScriptFile != NULL) {\r
     for (AliasListNode = (ALIAS_LIST*)GetFirstNode(&CurrentScriptFile->SubstList)\r
@@ -1498,21 +1691,21 @@ ShellConvertVariables (
       ;  AliasListNode = (ALIAS_LIST*)GetNextNode(&CurrentScriptFile->SubstList, &AliasListNode->Link)\r
    ){\r
     ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);\r
-    StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
+    StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
     }\r
-\r
-    //\r
-    // Remove non-existant environment variables in scripts only\r
-    //\r
-    StripUnreplacedEnvironmentVariables(NewCommandLine1);\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
-  StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);\r
-  \r
+  StrCpyS(NewCommandLine1, NewSize/sizeof(CHAR16), NewCommandLine2);\r
+\r
   FreePool(NewCommandLine2);\r
   FreePool(ItemTemp);\r
 \r
@@ -1526,19 +1719,14 @@ 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
 EFI_STATUS\r
-EFIAPI\r
 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  StdIn,\r
+  IN       SHELL_FILE_HANDLE  StdOut\r
   )\r
 {\r
   EFI_STATUS        Status;\r
@@ -1547,7 +1735,7 @@ RunSplitCommand(
   UINTN             Size1;\r
   UINTN             Size2;\r
   SPLIT_LIST        *Split;\r
-  SHELL_FILE_HANDLE *TempFileHandle;\r
+  SHELL_FILE_HANDLE TempFileHandle;\r
   BOOLEAN           Unicode;\r
 \r
   ASSERT(StdOut == NULL);\r
@@ -1571,11 +1759,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
@@ -1586,13 +1781,15 @@ RunSplitCommand(
   // make a SPLIT_LIST item and add to list\r
   //\r
   Split = AllocateZeroPool(sizeof(SPLIT_LIST));\r
-  ASSERT(Split != NULL);\r
+  if (Split == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
   Split->SplitStdIn   = StdIn;\r
   Split->SplitStdOut  = ConvertEfiFileProtocolToShellHandle(CreateFileInterfaceMem(Unicode), NULL);\r
   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
@@ -1604,10 +1801,10 @@ RunSplitCommand(
     Split->SplitStdOut  = Split->SplitStdIn;\r
   }\r
   Split->SplitStdIn   = TempFileHandle;\r
-  ShellInfoObject.NewEfiShellProtocol->SetFilePosition(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn), 0);\r
+  ShellInfoObject.NewEfiShellProtocol->SetFilePosition (Split->SplitStdIn, 0);\r
 \r
   if (!EFI_ERROR(Status)) {\r
-    Status = RunCommand(NextCommandLine, ExitStatus);\r
+    Status = RunCommand(NextCommandLine);\r
   }\r
 \r
   //\r
@@ -1619,11 +1816,11 @@ RunSplitCommand(
   //\r
   // Note that the original StdIn is now the StdOut...\r
   //\r
-  if (Split->SplitStdOut != NULL && Split->SplitStdOut != StdIn) {\r
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdOut));\r
+  if (Split->SplitStdOut != NULL) {\r
+    ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdOut);\r
   }\r
   if (Split->SplitStdIn != NULL) {\r
-    ShellInfoObject.NewEfiShellProtocol->CloseFile(ConvertShellHandleToEfiFileProtocol(Split->SplitStdIn));\r
+    ShellInfoObject.NewEfiShellProtocol->CloseFile (Split->SplitStdIn);\r
   }\r
 \r
   FreePool(Split);\r
@@ -1634,7 +1831,7 @@ RunSplitCommand(
 }\r
 \r
 /**\r
-  Take the original command line, substitute any variables, free \r
+  Take the original command line, substitute any variables, free\r
   the original string, return the modified copy.\r
 \r
   @param[in] CmdLine  pointer to the command line to update.\r
@@ -1643,7 +1840,6 @@ RunSplitCommand(
   @retval EFI_OUT_OF_RESOURCES  a memory allocation failed.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ShellSubstituteVariables(\r
   IN CHAR16 **CmdLine\r
   )\r
@@ -1659,7 +1855,7 @@ ShellSubstituteVariables(
 }\r
 \r
 /**\r
-  Take the original command line, substitute any alias in the first group of space delimited characters, free \r
+  Take the original command line, substitute any alias in the first group of space delimited characters, free\r
   the original string, return the modified copy.\r
 \r
   @param[in] CmdLine  pointer to the command line to update.\r
@@ -1668,7 +1864,6 @@ ShellSubstituteVariables(
   @retval EFI_OUT_OF_RESOURCES  a memory allocation failed.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ShellSubstituteAliases(\r
   IN CHAR16 **CmdLine\r
   )\r
@@ -1719,7 +1914,7 @@ ShellSubstituteAliases(
 \r
   SHELL_FREE_NON_NULL(*CmdLine);\r
   SHELL_FREE_NON_NULL(CommandName);\r
\r
+\r
   //\r
   // re-assign the passed in double pointer to point to our newly allocated buffer\r
   //\r
@@ -1732,7 +1927,7 @@ ShellSubstituteAliases(
   Takes the Argv[0] part of the command line and determine the meaning of it.\r
 \r
   @param[in] CmdName  pointer to the command line to update.\r
-  \r
+\r
   @retval Internal_Command    The name is an internal command.\r
   @retval File_Sys_Change     the name is a file system change.\r
   @retval Script_File_Name    the name is a NSH script file.\r
@@ -1740,7 +1935,6 @@ ShellSubstituteAliases(
   @retval Efi_Application     the name is an application (.EFI).\r
 **/\r
 SHELL_OPERATION_TYPES\r
-EFIAPI\r
 GetOperationType(\r
   IN CONST CHAR16 *CmdName\r
   )\r
@@ -1761,7 +1955,7 @@ GetOperationType(
   // 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
@@ -1791,7 +1985,7 @@ GetOperationType(
     SHELL_FREE_NON_NULL(FileWithPath);\r
     return (Efi_Application);\r
   }\r
-  \r
+\r
   SHELL_FREE_NON_NULL(FileWithPath);\r
   //\r
   // No clue what this is... return invalid flag...\r
@@ -1808,8 +2002,7 @@ GetOperationType(
   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.\r
   @retval EFI_NOT_FOUND         The operation type is unknown or invalid.\r
 **/\r
-EFI_STATUS \r
-EFIAPI\r
+EFI_STATUS\r
 IsValidSplit(\r
   IN CONST CHAR16 *CmdLine\r
   )\r
@@ -1845,12 +2038,12 @@ IsValidSplit(
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
     TempWalker = (CHAR16*)Temp;\r
-    GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine));\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
@@ -1868,7 +2061,6 @@ IsValidSplit(
   @retval EFI_ABORTED     CmdLine has at least one invalid command or application.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 VerifySplit(\r
   IN CONST CHAR16 *CmdLine\r
   )\r
@@ -1876,6 +2068,13 @@ VerifySplit(
   CONST CHAR16  *TempSpot;\r
   EFI_STATUS    Status;\r
 \r
+  //\r
+  // If this was the only item, then get out\r
+  //\r
+  if (!ContainsSplit(CmdLine)) {\r
+    return (EFI_SUCCESS);\r
+  }\r
+\r
   //\r
   // Verify up to the pipe or end character\r
   //\r
@@ -1885,34 +2084,30 @@ VerifySplit(
   }\r
 \r
   //\r
-  // If this was the only item, then get out\r
+  // recurse to verify the next item\r
   //\r
-  if (!ContainsSplit(CmdLine)) {\r
-    return (EFI_SUCCESS);\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
-  //\r
-  // recurse to verify the next item\r
-  //\r
-  TempSpot = FindSplit(CmdLine)+1;\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
@@ -1933,14 +2128,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
@@ -1956,7 +2146,6 @@ ProcessNewSplitCommandLine(
   @retval EFI_SUCCESS The operation was successful.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 ChangeMappedDrive(\r
   IN CONST CHAR16 *CmdLine\r
   )\r
@@ -1968,7 +2157,7 @@ ChangeMappedDrive(
   // make sure we are the right operation\r
   //\r
   ASSERT(CmdLine[(StrLen(CmdLine)-1)] == L':' && StrStr(CmdLine, L" ") == NULL);\r
-  \r
+\r
   //\r
   // Call the protocol API to do the work\r
   //\r
@@ -1992,16 +2181,15 @@ ChangeMappedDrive(
   @param[in,out] CmdLine        pointer to the command line to update\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 DoHelpUpdate(\r
   IN OUT CHAR16 **CmdLine\r
   )\r
 {\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
@@ -2012,25 +2200,26 @@ DoHelpUpdate(
 \r
   Walker = *CmdLine;\r
   while(Walker != NULL && *Walker != CHAR_NULL) {\r
-    LastWalker = Walker;\r
-    GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine));\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
-\r
-      //\r
-      // We know the space is sufficient since we just calculated it.\r
-      //\r
-      StrnCpy(NewCommandLine, L"help ", 5);\r
-      StrnCat(NewCommandLine, *CmdLine, StrLen(*CmdLine));\r
-      SHELL_FREE_NON_NULL(*CmdLine);\r
-      *CmdLine = NewCommandLine;\r
-      break;\r
     }\r
   }\r
 \r
@@ -2045,7 +2234,6 @@ DoHelpUpdate(
   @param[in] ErrorCode      the error code to put into lasterror.\r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 SetLastError(\r
   IN CONST SHELL_STATUS   ErrorCode\r
   )\r
@@ -2063,16 +2251,15 @@ SetLastError(
 }\r
 \r
 /**\r
-  Converts the command line to it's post-processed form.  this replaces variables and alias' per UEFI Shell spec.\r
+  Converts the command line to its post-processed form.  this replaces variables and alias' per UEFI Shell spec.\r
 \r
   @param[in,out] CmdLine        pointer to the command line to update\r
 \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
 ProcessCommandLineToFinal(\r
   IN OUT CHAR16 **CmdLine\r
   )\r
@@ -2114,24 +2301,22 @@ ProcessCommandLineToFinal(
 /**\r
   Run an internal shell command.\r
 \r
-  This API will upadate the shell's environment since these commands are libraries.\r
-  \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
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 RunInternalCommand(\r
   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
@@ -2140,7 +2325,7 @@ RunInternalCommand(
   SHELL_STATUS              CommandReturnedStatus;\r
   BOOLEAN                   LastError;\r
   CHAR16                    *Walker;\r
-  CHAR16                    *NewCmdLine;  \r
+  CHAR16                    *NewCmdLine;\r
 \r
   NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
   if (NewCmdLine == NULL) {\r
@@ -2156,7 +2341,7 @@ RunInternalCommand(
   //\r
   // get the argc and argv updated for internal commands\r
   //\r
-  Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, &Argv, &Argc);\r
+  Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, Internal_Command, &Argv, &Argc);\r
   if (!EFI_ERROR(Status)) {\r
     //\r
     // Run the internal command.\r
@@ -2164,6 +2349,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
@@ -2171,9 +2364,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
@@ -2198,13 +2388,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
@@ -2228,26 +2418,24 @@ 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
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 RunCommandOrFile(\r
   IN       SHELL_OPERATION_TYPES    Type,\r
   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
+  CHAR16                    *FullCommandWithPath;\r
   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
   SHELL_STATUS              CalleeExitStatus;\r
 \r
@@ -2258,12 +2446,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
@@ -2298,13 +2481,13 @@ RunCommandOrFile(
       }\r
       switch (Type) {\r
         case   Script_File_Name:\r
-          Status = RunScriptFile (\r
-                    CommandWithPath,\r
-                    NULL,\r
-                    CmdLine,\r
-                    ParamProtocol,\r
-                    &CalleeExitStatus\r
-                    );\r
+          FullCommandWithPath = FullyQualifyPath(CommandWithPath);\r
+          if (FullCommandWithPath == NULL) {\r
+            Status = RunScriptFile (CommandWithPath, NULL, CmdLine, ParamProtocol);\r
+          } else {\r
+            Status = RunScriptFile (FullCommandWithPath, NULL, CmdLine, ParamProtocol);\r
+            FreePool(FullCommandWithPath);\r
+          }\r
           break;\r
         case   Efi_Application:\r
           //\r
@@ -2324,9 +2507,7 @@ RunCommandOrFile(
             DevPath,\r
             CmdLine,\r
             NULL,\r
-            &StartStatus,\r
-            NULL,\r
-            NULL\r
+            &StartStatus\r
            );\r
 \r
           SHELL_FREE_NON_NULL(DevPath);\r
@@ -2337,6 +2518,10 @@ RunCommandOrFile(
             CalleeExitStatus = (SHELL_STATUS) StartStatus;\r
           }\r
 \r
+          if (CommandStatus != NULL) {\r
+            *CommandStatus = CalleeExitStatus;\r
+          }\r
+\r
           //\r
           // Update last error status.\r
           //\r
@@ -2359,10 +2544,6 @@ RunCommandOrFile(
 \r
   SHELL_FREE_NON_NULL(CommandWithPath);\r
 \r
-  if (ExitStatus != NULL) {\r
-    *ExitStatus = CalleeExitStatus;\r
-  }\r
-\r
   return (Status);\r
 }\r
 \r
@@ -2373,21 +2554,18 @@ 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
 **/\r
 EFI_STATUS\r
-EFIAPI\r
 SetupAndRunCommandOrFile(\r
   IN   SHELL_OPERATION_TYPES          Type,\r
   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
@@ -2395,6 +2573,7 @@ SetupAndRunCommandOrFile(
   SHELL_FILE_HANDLE         OriginalStdOut;\r
   SHELL_FILE_HANDLE         OriginalStdErr;\r
   SYSTEM_TABLE_INFO         OriginalSystemTableInfo;\r
+  CONST SCRIPT_FILE         *ConstScriptFile;\r
 \r
   //\r
   // Update the StdIn, StdOut, and StdErr for redirection to environment variables, files, etc... unicode and ASCII\r
@@ -2407,20 +2586,19 @@ SetupAndRunCommandOrFile(
   //\r
   if (!EFI_ERROR(Status)) {\r
     TrimSpaces(&CmdLine);\r
-    Status = RunCommandOrFile(\r
-              Type,\r
-              CmdLine,\r
-              FirstParameter,\r
-              ParamProtocol,\r
-              ExitStatus\r
-              );\r
+    Status = RunCommandOrFile(Type, CmdLine, FirstParameter, ParamProtocol, CommandStatus);\r
   }\r
 \r
   //\r
   // Now print errors\r
   //\r
   if (EFI_ERROR(Status)) {\r
-    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));\r
+    ConstScriptFile = ShellCommandGetCurrentScriptFile();\r
+    if (ConstScriptFile == NULL || ConstScriptFile->CurrentCommand == NULL) {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));\r
+    } else {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR_SCRIPT), ShellInfoObject.HiiHandle, (VOID*)(Status), ConstScriptFile->CurrentCommand->Line);\r
+    }\r
   }\r
 \r
   //\r
@@ -2434,20 +2612,19 @@ SetupAndRunCommandOrFile(
 /**\r
   Function will process and run a command line.\r
 \r
-  This will determine if the command line represents an internal shell \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
-  @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
@@ -2455,6 +2632,7 @@ RunCommand(
   CHAR16                    *FirstParameter;\r
   CHAR16                    *TempWalker;\r
   SHELL_OPERATION_TYPES     Type;\r
+  CONST CHAR16              *CurDir;\r
 \r
   ASSERT(CmdLine != NULL);\r
   if (StrLen(CmdLine) == 0) {\r
@@ -2475,7 +2653,7 @@ RunCommand(
   // 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
-  // Afterward, again remove spaces, in case any were between the last command-parameter and '#'.\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
@@ -2504,13 +2682,13 @@ 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
+  }\r
 \r
   //\r
   // We need the first parameter information so we can determine the operation type\r
@@ -2521,71 +2699,70 @@ RunCommand(
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
   TempWalker = CleanOriginal;\r
-  GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal));\r
-\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
-  // Depending on the first parameter we change the behavior\r
+  // Check whether the current file system still exists. If not exist, we need update "cwd" and gShellCurMapping.\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(\r
-                Type,\r
-                CleanOriginal,\r
-                FirstParameter,\r
-                ShellInfoObject.NewShellParametersProtocol,\r
-                ExitStatus\r
-                );\r
-      break;\r
-    default:\r
+  CurDir = EfiShellGetCurDir (NULL);\r
+  if (CurDir != NULL) {\r
+    if (EFI_ERROR(ShellFileExists (CurDir))) {\r
       //\r
-      // Whatever was typed, it was invalid.\r
+      // EfiShellSetCurDir() cannot set current directory to NULL.\r
+      // EfiShellSetEnv() is not allowed to set the "cwd" variable.\r
+      // Only InternalEfiShellSetEnv () is allowed setting the "cwd" variable.\r
       //\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
-      SetLastError(SHELL_NOT_FOUND);\r
-      break;\r
+      InternalEfiShellSetEnv (L"cwd", NULL, TRUE);\r
+      gShellCurMapping = NULL;\r
+    }\r
   }\r
\r
+\r
   SHELL_FREE_NON_NULL(CleanOriginal);\r
   SHELL_FREE_NON_NULL(FirstParameter);\r
 \r
   return (Status);\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
-  this is a valid command.  It only checks for invalid characters.\r
+  Function will process and run a command line.\r
 \r
-  @param[in] CommandName    The name to check\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 TRUE              CommandName could be a command name\r
-  @retval FALSE             CommandName could not be a valid command name\r
+  @retval EFI_SUCCESS     The command was completed.\r
+  @retval EFI_ABORTED     The command's operation was aborted.\r
 **/\r
-BOOLEAN\r
-EFIAPI\r
-IsValidCommandName(\r
-  IN CONST CHAR16     *CommandName\r
+EFI_STATUS\r
+RunCommand(\r
+  IN CONST CHAR16   *CmdLine\r
   )\r
 {\r
-  UINTN Count;\r
-  if (CommandName == NULL) {\r
-    ASSERT(FALSE);\r
-    return (FALSE);\r
-  }\r
-  for ( Count = 0\r
-      ; Count < sizeof(InvalidChars) / sizeof(InvalidChars[0])\r
-      ; Count++\r
-     ){\r
-    if (ScanMem16(CommandName, StrSize(CommandName), InvalidChars[Count]) != NULL) {\r
-      return (FALSE);\r
-    }\r
-  }\r
-  return (TRUE);\r
+  return (RunShellCommand(CmdLine, NULL));\r
 }\r
 \r
 /**\r
@@ -2594,21 +2771,18 @@ 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
@@ -2619,13 +2793,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
@@ -2652,7 +2825,12 @@ RunScriptFileHandle (
       DeleteScriptFileStruct(NewScriptFile);\r
       return (EFI_OUT_OF_RESOURCES);\r
     }\r
-    for (LoopVar = 0 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
+    //\r
+    // Put the full path of the script file into Argv[0] as required by section\r
+    // 3.6.2 of version 2.2 of the shell specification.\r
+    //\r
+    NewScriptFile->Argv[0] = StrnCatGrow(&NewScriptFile->Argv[0], NULL, NewScriptFile->ScriptName, 0);\r
+    for (LoopVar = 1 ; LoopVar < 10 && LoopVar < NewScriptFile->Argc; LoopVar++) {\r
       ASSERT(NewScriptFile->Argv[LoopVar] == NULL);\r
       NewScriptFile->Argv[LoopVar] = StrnCatGrow(&NewScriptFile->Argv[LoopVar], NULL, ShellInfoObject.NewShellParametersProtocol->Argv[LoopVar], 0);\r
       if (NewScriptFile->Argv[LoopVar] == NULL) {\r
@@ -2700,12 +2878,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
@@ -2717,7 +2895,13 @@ RunScriptFileHandle (
       ; // conditional increment in the body of the loop\r
   ){\r
     ASSERT(CommandLine2 != NULL);\r
-    StrnCpy(CommandLine2, NewScriptFile->CurrentCommand->Cl, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\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
@@ -2738,7 +2922,11 @@ RunScriptFileHandle (
       //\r
       // Due to variability in starting the find and replace action we need to have both buffers the same.\r
       //\r
-      StrnCpy(CommandLine, CommandLine2, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\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
@@ -2746,51 +2934,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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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, FALSE);\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
-      StrnCpy(CommandLine2, CommandLine, PcdGet16(PcdShellPrintBufferSize)/sizeof(CHAR16)-1);\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
@@ -2809,7 +3001,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
@@ -2831,7 +3023,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
@@ -2839,24 +3031,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
@@ -2875,6 +3068,7 @@ RunScriptFileHandle (
         NewScriptFile->CurrentCommand->Reset = TRUE;\r
       }\r
     }\r
+    RestoreBufferList(&OldBufferList);\r
   }\r
 \r
 \r
@@ -2888,11 +3082,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
@@ -2904,18 +3093,14 @@ 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
@@ -2930,7 +3115,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
@@ -2942,7 +3127,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
@@ -2950,15 +3135,49 @@ 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
+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