]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Application/Shell/Shell.c
ShellPkg: Skip leading tabs when processing command line and scripts
[mirror_edk2.git] / ShellPkg / Application / Shell / Shell.c
index 878a3852a5e56c4cdd5c4b21186a6b585f19a3b3..1b52692ecec79793647ad32aec287171451938a3 100644 (file)
@@ -1,7 +1,8 @@
 /** @file\r
   This is THE shell (application)\r
 \r
-  Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2013, 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
@@ -23,22 +24,24 @@ SHELL_INFO ShellInfoObject = {
   FALSE,\r
   FALSE,\r
   {\r
-    0,\r
-    0,\r
-    0,\r
-    0,\r
-    0,\r
-    0,\r
-    0,\r
-    0,\r
-    0,\r
+    {{\r
+      0,\r
+      0,\r
+      0,\r
+      0,\r
+      0,\r
+      0,\r
+      0,\r
+      0,\r
+      0\r
+    }},\r
     0,\r
     NULL,\r
     NULL\r
   },\r
-  {0,0},\r
+  {{NULL, NULL}, NULL},\r
   {\r
-    {0,0},\r
+    {{NULL, NULL}, NULL},\r
     0,\r
     0,\r
     TRUE\r
@@ -50,8 +53,12 @@ SHELL_INFO ShellInfoObject = {
   NULL,\r
   NULL,\r
   NULL,\r
-  {0,0,NULL,NULL},\r
-  {0,0},\r
+  {{NULL, NULL}, NULL, NULL},\r
+  {{NULL, NULL}, NULL, NULL},\r
+  NULL,\r
+  NULL,\r
+  NULL,\r
+  NULL,\r
   NULL,\r
   NULL,\r
   NULL,\r
@@ -290,11 +297,28 @@ UefiMain (
         0,\r
         gST->ConOut->Mode->CursorRow,\r
         NULL,\r
-        STRING_TOKEN (STR_VER_OUTPUT_MAIN),\r
+        STRING_TOKEN (STR_VER_OUTPUT_MAIN_SHELL),\r
         ShellInfoObject.HiiHandle,\r
         SupportLevel[PcdGet8(PcdShellSupportLevel)],\r
         gEfiShellProtocol->MajorVersion,\r
-        gEfiShellProtocol->MinorVersion,\r
+        gEfiShellProtocol->MinorVersion\r
+       );\r
+\r
+      ShellPrintHiiEx (\r
+        -1,\r
+        -1,\r
+        NULL,\r
+        STRING_TOKEN (STR_VER_OUTPUT_MAIN_SUPPLIER),\r
+        ShellInfoObject.HiiHandle,\r
+        (CHAR16 *) PcdGetPtr (PcdShellSupplier)\r
+       );\r
+\r
+      ShellPrintHiiEx (\r
+        -1,\r
+        -1,\r
+        NULL,\r
+        STRING_TOKEN (STR_VER_OUTPUT_MAIN_UEFI),\r
+        ShellInfoObject.HiiHandle,\r
         (gST->Hdr.Revision&0xffff0000)>>16,\r
         (gST->Hdr.Revision&0x0000ffff),\r
         gST->FirmwareVendor,\r
@@ -375,7 +399,7 @@ UefiMain (
         Status = DoStartupScript(ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
       }\r
 \r
-      if (!ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
+      if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit && !ShellCommandGetExit() && (PcdGet8(PcdShellSupportLevel) >= 3 || PcdGetBool(PcdShellForceConsole)) && !EFI_ERROR(Status) && !ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
         //\r
         // begin the UI waiting loop\r
         //\r
@@ -435,7 +459,7 @@ UefiMain (
   }\r
   if (ShellInfoObject.NewEfiShellProtocol != NULL){\r
     if (ShellInfoObject.NewEfiShellProtocol->IsRootShell()){\r
-      ShellInfoObject.NewEfiShellProtocol->SetEnv(L"cwd", L"", TRUE);\r
+      InternalEfiShellSetEnv(L"cwd", NULL, TRUE);\r
     }\r
     CleanUpShellProtocol(ShellInfoObject.NewEfiShellProtocol);\r
     DEBUG_CODE(ShellInfoObject.NewEfiShellProtocol = NULL;);\r
@@ -636,6 +660,7 @@ STATIC CONST SHELL_PARAM_ITEM mShellParamList[] = {
   {L"-noversion",     TypeFlag},\r
   {L"-startup",       TypeFlag},\r
   {L"-delay",         TypeValue},\r
+  {L"-_exit",         TypeFlag},\r
   {NULL, TypeMax}\r
   };\r
 \r
@@ -743,6 +768,7 @@ ProcessCommandLine(
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoMap        = ShellCommandLineGetFlag(Package, L"-nomap");\r
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoVersion    = ShellCommandLineGetFlag(Package, L"-noversion");\r
   ShellInfoObject.ShellInitSettings.BitUnion.Bits.Delay        = ShellCommandLineGetFlag(Package, L"-delay");\r
+  ShellInfoObject.ShellInitSettings.BitUnion.Bits.Exit         = ShellCommandLineGetFlag(Package, L"-_exit");\r
 \r
   ShellInfoObject.ShellInitSettings.Delay = 5;\r
 \r
@@ -827,20 +853,22 @@ DoStartupScript(
     return (EFI_SUCCESS);\r
   }\r
 \r
+  gST->ConOut->EnableCursor(gST->ConOut, FALSE);\r
   //\r
   // print out our warning and see if they press a key\r
   //\r
-  for ( Status = EFI_UNSUPPORTED, Delay = ShellInfoObject.ShellInitSettings.Delay * 10\r
+  for ( Status = EFI_UNSUPPORTED, Delay = ShellInfoObject.ShellInitSettings.Delay\r
       ; Delay != 0 && EFI_ERROR(Status)\r
       ; Delay--\r
      ){\r
-    ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay/10);\r
-    gBS->Stall (100000);\r
+    ShellPrintHiiEx(0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_SHELL_STARTUP_QUESTION), ShellInfoObject.HiiHandle, Delay);\r
+    gBS->Stall (1000000);\r
     if (!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleIn) {\r
       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
     }\r
   }\r
   ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_CRLF), ShellInfoObject.HiiHandle);\r
+  gST->ConOut->EnableCursor(gST->ConOut, TRUE);\r
 \r
   //\r
   // ESC was pressed\r
@@ -1075,6 +1103,7 @@ ShellConvertVariables (
   CHAR16              *NewCommandLine1;\r
   CHAR16              *NewCommandLine2;\r
   CHAR16              *Temp;\r
+  CHAR16              *Temp2;\r
   UINTN               ItemSize;\r
   CHAR16              *ItemTemp;\r
   SCRIPT_FILE         *CurrentScriptFile;\r
@@ -1132,15 +1161,6 @@ ShellConvertVariables (
     }\r
   }\r
 \r
-  //\r
-  // Quick out if none were found...\r
-  //\r
-  if (NewSize == StrSize(OriginalCommandLine)) {\r
-    ASSERT(Temp == NULL);\r
-    Temp = StrnCatGrow(&Temp, NULL, OriginalCommandLine, 0);\r
-    return (Temp);\r
-  }\r
-\r
   //\r
   // now do the replacements...\r
   //\r
@@ -1172,8 +1192,51 @@ ShellConvertVariables (
     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
+    }\r
+\r
   }\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
+  \r
   FreePool(NewCommandLine2);\r
   FreePool(ItemTemp);\r
 \r
@@ -1308,12 +1371,13 @@ RunCommand(
   )\r
 {\r
   EFI_STATUS                Status;\r
+  EFI_STATUS                StatusCode;\r
   CHAR16                    *CommandName;\r
   SHELL_STATUS              ShellStatus;\r
   UINTN                     Argc;\r
   CHAR16                    **Argv;\r
   BOOLEAN                   LastError;\r
-  CHAR16                    LeString[11];\r
+  CHAR16                    LeString[19];\r
   CHAR16                    *PostAliasCmdLine;\r
   UINTN                     PostAliasSize;\r
   CHAR16                    *PostVariableCmdLine;\r
@@ -1349,12 +1413,31 @@ RunCommand(
   if (CleanOriginal == NULL) {\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
+\r
+  //\r
+  // Remove any spaces and tabs at the beginning of the string.\r
+  //\r
+  while ((CleanOriginal[0] == L' ') || (CleanOriginal[0] == L'\t')) {\r
+    CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0]));\r
+  }\r
+\r
+  //\r
+  // Handle case that passed in command line is just 1 or more " " characters.\r
+  //\r
+  if (StrLen (CleanOriginal) == 0) {\r
+    if (CleanOriginal != NULL) {\r
+      FreePool(CleanOriginal);\r
+      CleanOriginal = NULL;\r
+    }\r
+    return (EFI_SUCCESS);\r
+  }\r
+\r
+  //\r
+  // Remove any spaces at the end of the string.\r
+  //\r
   while (CleanOriginal[StrLen(CleanOriginal)-1] == L' ') {\r
     CleanOriginal[StrLen(CleanOriginal)-1] = CHAR_NULL;\r
   }\r
-  while (CleanOriginal[0] == L' ') {\r
-    CopyMem(CleanOriginal, CleanOriginal+1, StrSize(CleanOriginal) - sizeof(CleanOriginal[0]));\r
-  }\r
 \r
   CommandName = NULL;\r
   if (StrStr(CleanOriginal, L" ") == NULL){\r
@@ -1510,10 +1593,15 @@ RunCommand(
         if (!EFI_ERROR(Status))  {\r
           Status = ShellCommandRunCommandHandler(ShellInfoObject.NewShellParametersProtocol->Argv[0], &ShellStatus, &LastError);\r
           ASSERT_EFI_ERROR(Status);\r
-          UnicodeSPrint(LeString, sizeof(LeString)*sizeof(LeString[0]), L"0x%08x", ShellStatus);\r
-          DEBUG_CODE(InternalEfiShellSetEnv(L"DebugLasterror", LeString, TRUE););\r
+\r
+          if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
+            UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ShellStatus);\r
+          } else {\r
+            UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", ShellStatus);\r
+          }\r
+          DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
           if (LastError) {\r
-            InternalEfiShellSetEnv(L"Lasterror", LeString, TRUE);\r
+            InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
           }\r
           //\r
           // Pass thru the exitcode from the app.\r
@@ -1539,6 +1627,14 @@ RunCommand(
         }\r
         if (CommandWithPath == NULL || ShellIsDirectory(CommandWithPath) == EFI_SUCCESS) {\r
           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, ShellInfoObject.NewShellParametersProtocol->Argv[0]);\r
+\r
+          if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
+            UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", EFI_NOT_FOUND);\r
+          } else {\r
+            UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", EFI_NOT_FOUND);\r
+          }\r
+          DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
+          InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
         } else {\r
           //\r
           // Check if it's a NSH (script) file.\r
@@ -1555,11 +1651,30 @@ RunCommand(
               DevPath,\r
               PostVariableCmdLine,\r
               NULL,\r
-              NULL\r
+              &StatusCode\r
              );\r
+\r
+            //\r
+            // Update last error status.\r
+            //\r
+            if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
+              UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", StatusCode);\r
+            } else {\r
+              UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", StatusCode);\r
+            }\r
+            DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
+            InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
           }\r
         }\r
       }\r
+\r
+      //\r
+      // Print some error info.\r
+      //\r
+      if (EFI_ERROR(Status)) {\r
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_ERROR), ShellInfoObject.HiiHandle, (VOID*)(Status));\r
+      }\r
+\r
       CommandName = StrnCatGrow(&CommandName, NULL, ShellInfoObject.NewShellParametersProtocol->Argv[0], 0);\r
 \r
       RestoreArgcArgv(ShellInfoObject.NewShellParametersProtocol, &Argv, &Argc);\r
@@ -1830,9 +1945,15 @@ RunScriptFileHandle (
             Status = RunCommand(CommandLine3+1);\r
 \r
             //\r
-            // Now restore the pre-'@' echo state.\r
+            // If command was "@echo -off" or "@echo -on" then don't restore echo state\r
             //\r
-            ShellCommandSetEchoState(PreCommandEchoState);\r
+            if (StrCmp (L"@echo -off", CommandLine3) != 0 &&\r
+                StrCmp (L"@echo -on", CommandLine3) != 0) {\r
+              //\r
+              // Now restore the pre-'@' echo state.\r
+              //\r
+              ShellCommandSetEchoState(PreCommandEchoState);\r
+            }\r
           } else {\r
             if (ShellCommandGetEchoState()) {\r
               CurDir = ShellInfoObject.NewEfiShellProtocol->GetEnv(L"cwd");\r
@@ -1848,14 +1969,20 @@ RunScriptFileHandle (
         }\r
 \r
         if (ShellCommandGetScriptExit()) {\r
-          UnicodeSPrint(LeString, sizeof(LeString)*sizeof(LeString[0]), L"0x%Lx", ShellCommandGetExitCode());\r
-          DEBUG_CODE(InternalEfiShellSetEnv(L"DebugLasterror", LeString, TRUE););\r
-          InternalEfiShellSetEnv(L"Lasterror", LeString, TRUE);\r
+          //\r
+          // ShellCommandGetExitCode() always returns a UINT64\r
+          //\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
           break;\r
         }\r
+        if (ShellGetExecutionBreakFlag()) {\r
+          break;\r
+        }\r
         if (EFI_ERROR(Status)) {\r
           break;\r
         }\r