]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLib/UefiShellLib.c
ShellPkg: Refactor string manipulation in UefiShellLib command
[mirror_edk2.git] / ShellPkg / Library / UefiShellLib / UefiShellLib.c
index a0a7da87daec09f3d4d352a9ca6f965cc6fe384b..819c9f03ac16f4ae779d6acaa343a3416b25a046 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Provides interface to shell functionality for shell commands and applications.\r
 \r
-  Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -1175,7 +1175,7 @@ ShellSetEnvironmentVariable (
   The CommandLine is executed from the current working directory on the current\r
   device.\r
 \r
-  The EnvironmentVariables and Status parameters are ignored in a pre-UEFI Shell 2.0\r
+  The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0\r
   environment.  The values pointed to by the parameters will be unchanged by the\r
   ShellExecute() function.  The Output parameter has no effect in a\r
   UEFI Shell 2.0 environment.\r
@@ -1203,6 +1203,7 @@ ShellExecute (
   OUT EFI_STATUS                *Status OPTIONAL\r
   )\r
 {\r
+  EFI_STATUS                CmdStatus;\r
   //\r
   // Check for UEFI Shell 2.0 protocols\r
   //\r
@@ -1221,16 +1222,29 @@ ShellExecute (
   //\r
   if (mEfiShellEnvironment2 != NULL) {\r
     //\r
-    // Call EFI Shell version (not using EnvironmentVariables or Status parameters)\r
+    // Call EFI Shell version.\r
     // Due to oddity in the EFI shell we want to dereference the ParentHandle here\r
     //\r
-    return (mEfiShellEnvironment2->Execute(*ParentHandle,\r
+    CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,\r
                                           CommandLine,\r
                                           Output));\r
+    //\r
+    // No Status output parameter so just use the returned status\r
+    //\r
+    if (Status != NULL) {\r
+      *Status = CmdStatus;\r
+    }\r
+    //\r
+    // If there was an error, we can't tell if it was from the command or from\r
+    // the Execute() function, so we'll just assume the shell ran successfully\r
+    // and the error came from the command.\r
+    //\r
+    return EFI_SUCCESS;\r
   }\r
 \r
   return (EFI_UNSUPPORTED);\r
 }\r
+\r
 /**\r
   Retreives the current directory path\r
 \r
@@ -1416,26 +1430,30 @@ InternalShellConvertFileListType (
     //\r
     // allocate new space to copy strings and structure\r
     //\r
-    NewInfo->FullName     = AllocateZeroPool(StrSize(OldInfo->FullName));\r
-    NewInfo->FileName     = AllocateZeroPool(StrSize(OldInfo->FileName));\r
-    NewInfo->Info         = AllocateZeroPool((UINTN)OldInfo->Info->Size);\r
+    NewInfo->FullName     = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);\r
+    NewInfo->FileName     = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);\r
+    NewInfo->Info         = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);\r
 \r
     //\r
     // make sure all the memory allocations were sucessful\r
     //\r
     if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {\r
+      //\r
+      // Free the partially allocated new node\r
+      //\r
+      SHELL_FREE_NON_NULL(NewInfo->FullName);\r
+      SHELL_FREE_NON_NULL(NewInfo->FileName);\r
+      SHELL_FREE_NON_NULL(NewInfo->Info);\r
+      SHELL_FREE_NON_NULL(NewInfo);\r
+\r
+      //\r
+      // Free the previously converted stuff\r
+      //\r
       ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));\r
       ListHead = NULL;\r
       break;\r
     }\r
 \r
-    //\r
-    // Copt the strings and structure\r
-    //\r
-    StrCpy(NewInfo->FullName, OldInfo->FullName);\r
-    StrCpy(NewInfo->FileName, OldInfo->FileName);\r
-    gBS->CopyMem (NewInfo->Info, OldInfo->Info, (UINTN)OldInfo->Info->Size);\r
-\r
     //\r
     // add that to the list\r
     //\r
@@ -1447,8 +1465,8 @@ InternalShellConvertFileListType (
   Opens a group of files based on a path.\r
 \r
   This function uses the Arg to open all the matching files. Each matched\r
-  file has a SHELL_FILE_ARG structure to record the file information. These\r
-  structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG\r
+  file has a SHELL_FILE_INFO structure to record the file information. These\r
+  structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO\r
   structures from ListHead to access each file. This function supports wildcards\r
   and will process '?' and '*' as such.  the list must be freed with a call to\r
   ShellCloseFileMetaArg().\r
@@ -1598,6 +1616,7 @@ ShellCloseFileMetaArg (
       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);\r
       FreePool((EFI_SHELL_FILE_INFO_NO_CONST*)Node);\r
     }\r
+    SHELL_FREE_NON_NULL(*ListHead);\r
     return EFI_SUCCESS;\r
   }\r
 \r
@@ -1656,8 +1675,8 @@ ShellFindFilePath (
     if (TestPath == NULL) {\r
       return (NULL);\r
     }\r
-    StrCpy(TestPath, Path);\r
-    StrCat(TestPath, FileName);\r
+    StrnCpy(TestPath, Path, Size/sizeof(CHAR16) - 1);\r
+    StrnCat(TestPath, FileName, Size/sizeof(CHAR16) - 1 - StrLen(TestPath));\r
     Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
     if (!EFI_ERROR(Status)){\r
       if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
@@ -1689,12 +1708,12 @@ ShellFindFilePath (
           *TempChar = CHAR_NULL;\r
         }\r
         if (TestPath[StrLen(TestPath)-1] != L'\\') {\r
-          StrCat(TestPath, L"\\");\r
+          StrnCat(TestPath, L"\\", Size/sizeof(CHAR16) - 1 - StrLen(TestPath));\r
         }\r
         if (FileName[0] == L'\\') {\r
           FileName++;\r
         }\r
-        StrCat(TestPath, FileName);\r
+        StrnCat(TestPath, FileName, Size/sizeof(CHAR16) - 1 - StrLen(TestPath));\r
         if (StrStr(Walker, L";") != NULL) {\r
           Walker = StrStr(Walker, L";") + 1;\r
         } else {\r
@@ -1763,9 +1782,9 @@ ShellFindFilePathEx (
     return (NULL);\r
   }\r
   for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension;  TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){\r
-    StrCpy(TestPath, FileName);\r
+    StrnCpy(TestPath, FileName, Size/sizeof(CHAR16) - 1);\r
     if (ExtensionWalker != NULL) {\r
-      StrCat(TestPath, ExtensionWalker);\r
+      StrnCat(TestPath, ExtensionWalker, Size/sizeof(CHAR16) - 1 - StrLen(TestPath));\r
     }\r
     TempChar = StrStr(TestPath, L";");\r
     if (TempChar != NULL) {\r
@@ -1888,7 +1907,7 @@ InternalIsFlag (
   //\r
   // If we accept numbers then dont return TRUE. (they will be values)\r
   //\r
-  if (((Name[0] == L'-' || Name[0] == L'+') && ShellIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers) {\r
+  if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE)) && AlwaysAllowNumbers) {\r
     return (FALSE);\r
   }\r
 \r
@@ -1948,6 +1967,7 @@ InternalCommandLineParse (
   UINTN                         ValueSize;\r
   UINTN                         Count;\r
   CONST CHAR16                  *TempPointer;\r
+  UINTN                         CurrentValueSize;\r
 \r
   CurrentItemPackage = NULL;\r
   GetItemValue = 0;\r
@@ -2003,13 +2023,12 @@ InternalCommandLineParse (
         *CheckPackage = NULL;\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
-      CurrentItemPackage->Name  = AllocateZeroPool(StrSize(Argv[LoopCounter]));\r
+      CurrentItemPackage->Name  = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);\r
       if (CurrentItemPackage->Name == NULL) {\r
         ShellCommandLineFreeVarList(*CheckPackage);\r
         *CheckPackage = NULL;\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
-      StrCpy(CurrentItemPackage->Name,  Argv[LoopCounter]);\r
       CurrentItemPackage->Type  = CurrentItemType;\r
       CurrentItemPackage->OriginalPosition = (UINTN)(-1);\r
       CurrentItemPackage->Value = NULL;\r
@@ -2047,30 +2066,32 @@ InternalCommandLineParse (
       // get the item VALUE for a previous flag\r
       //\r
       if (StrStr(Argv[LoopCounter], L" ") == NULL) {\r
-        CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16), CurrentItemPackage->Value);\r
+        CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+        CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);\r
         ASSERT(CurrentItemPackage->Value != NULL);\r
         if (ValueSize == 0) {\r
-          StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
+          StrnCpy(CurrentItemPackage->Value, Argv[LoopCounter], CurrentValueSize/sizeof(CHAR16) - 1);\r
         } else {\r
-          StrCat(CurrentItemPackage->Value, L" ");\r
-          StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
+          StrnCat(CurrentItemPackage->Value, L" ", CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
+          StrnCat(CurrentItemPackage->Value, Argv[LoopCounter], CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
         }\r
         ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
       } else {\r
         //\r
         // the parameter has spaces.  must be quoted.\r
         //\r
-        CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16) + sizeof(CHAR16) + sizeof(CHAR16), CurrentItemPackage->Value);\r
+        CurrentValueSize =  ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16) + sizeof(CHAR16) + sizeof(CHAR16);\r
+        CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);\r
         ASSERT(CurrentItemPackage->Value != NULL);\r
         if (ValueSize == 0) {\r
-          StrCpy(CurrentItemPackage->Value, L"\"");\r
-          StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-          StrCat(CurrentItemPackage->Value, L"\"");\r
+          StrnCpy(CurrentItemPackage->Value, L"\"", CurrentValueSize/sizeof(CHAR16) - 1);\r
+          StrnCat(CurrentItemPackage->Value, Argv[LoopCounter], CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
+          StrnCat(CurrentItemPackage->Value, L"\"", CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
         } else {\r
-          StrCat(CurrentItemPackage->Value, L" ");\r
-          StrCat(CurrentItemPackage->Value, L"\"");\r
-          StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-          StrCat(CurrentItemPackage->Value, L"\"");\r
+          StrnCat(CurrentItemPackage->Value, L" ", CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
+          StrnCat(CurrentItemPackage->Value, L"\"", CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
+          StrnCat(CurrentItemPackage->Value, Argv[LoopCounter], CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
+          StrnCat(CurrentItemPackage->Value, L"\"", CurrentValueSize/sizeof(CHAR16) - 1 - StrLen(CurrentItemPackage->Value));\r
        }\r
         ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
       }\r
@@ -2098,13 +2119,12 @@ InternalCommandLineParse (
       }\r
       CurrentItemPackage->Name  = NULL;\r
       CurrentItemPackage->Type  = TypePosition;\r
-      CurrentItemPackage->Value = AllocateZeroPool(StrSize(TempPointer));\r
+      CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);\r
       if (CurrentItemPackage->Value == NULL) {\r
         ShellCommandLineFreeVarList(*CheckPackage);\r
         *CheckPackage = NULL;\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
-      StrCpy(CurrentItemPackage->Value, TempPointer);\r
       CurrentItemPackage->OriginalPosition = Count++;\r
       InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
     } else {\r
@@ -2112,10 +2132,7 @@ InternalCommandLineParse (
       // this was a non-recognised flag... error!\r
       //\r
       if (ProblemParam != NULL) {\r
-        *ProblemParam = AllocateZeroPool(StrSize(Argv[LoopCounter]));\r
-        if (*ProblemParam != NULL) {\r
-          StrCpy(*ProblemParam, Argv[LoopCounter]);\r
-        }\r
+        *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);\r
       }\r
       ShellCommandLineFreeVarList(*CheckPackage);\r
       *CheckPackage = NULL;\r
@@ -2582,7 +2599,7 @@ ShellCopySearchAndReplace(
   if (Replace == NULL) {\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
-  NewString = SetMem16(NewString, NewSize, CHAR_NULL);\r
+  NewString = ZeroMem(NewString, NewSize);\r
   while (*SourceString != CHAR_NULL) {\r
     //\r
     // if we find the FindTarget and either Skip == FALSE or Skip  and we\r
@@ -2597,7 +2614,7 @@ ShellCopySearchAndReplace(
         FreePool(Replace);\r
         return (EFI_BUFFER_TOO_SMALL);\r
       }\r
-      StrCat(NewString, Replace);\r
+      StrnCat(NewString, Replace, NewSize/sizeof(CHAR16) - 1 - StrLen(NewString));\r
     } else {\r
       Size = StrSize(NewString);\r
       if (Size + sizeof(CHAR16) > NewSize) {\r
@@ -3056,6 +3073,32 @@ ShellIsFileInPath(
   return (Status);\r
 }\r
 \r
+/**\r
+  Function return the number converted from a hex representation of a number.\r
+\r
+  Note: this function cannot be used when (UINTN)(-1), (0xFFFFFFFF) may be a valid\r
+  result.  Use ShellConvertStringToUint64 instead.\r
+\r
+  @param[in] String   String representation of a number.\r
+\r
+  @return             The unsigned integer result of the conversion.\r
+  @retval (UINTN)(-1) An error occured.\r
+**/\r
+UINTN\r
+EFIAPI\r
+ShellHexStrToUintn(\r
+  IN CONST CHAR16 *String\r
+  )\r
+{\r
+  UINT64        RetVal;\r
+\r
+  if (!EFI_ERROR(ShellConvertStringToUint64(String, &RetVal, TRUE, TRUE))) {\r
+    return ((UINTN)RetVal);\r
+  }\r
+  \r
+  return ((UINTN)(-1));\r
+}\r
+\r
 /**\r
   Function to determine whether a string is decimal or hex representation of a number\r
   and return the number converted from the string.  Spaces are always skipped.\r
@@ -3253,7 +3296,9 @@ ShellPromptForResponse (
       //\r
       gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
       Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-      ASSERT_EFI_ERROR(Status);\r
+      if (EFI_ERROR(Status)) {\r
+        break;\r
+      }\r
       ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
       if (Key.UnicodeChar == L'Q' || Key.UnicodeChar ==L'q') {\r
         *Resp = ShellPromptResponseQuit;\r
@@ -3270,9 +3315,15 @@ ShellPromptForResponse (
       //\r
       *Resp = ShellPromptResponseMax;\r
       while (*Resp == ShellPromptResponseMax) {\r
+        if (ShellGetExecutionBreakFlag()) {\r
+          Status = EFI_ABORTED;\r
+          break;\r
+        }\r
         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-        ASSERT_EFI_ERROR(Status);\r
+        if (EFI_ERROR(Status)) {\r
+          break;\r
+        }\r
         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
         switch (Key.UnicodeChar) {\r
           case L'Y':\r
@@ -3298,9 +3349,15 @@ ShellPromptForResponse (
       //\r
       *Resp = ShellPromptResponseMax;\r
       while (*Resp == ShellPromptResponseMax) {\r
+        if (ShellGetExecutionBreakFlag()) {\r
+          Status = EFI_ABORTED;\r
+          break;\r
+        }\r
         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-        ASSERT_EFI_ERROR(Status);\r
+        if (EFI_ERROR(Status)) {\r
+          break;\r
+        }\r
         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
         switch (Key.UnicodeChar) {\r
           case L'Y':\r
@@ -3332,10 +3389,16 @@ ShellPromptForResponse (
       //\r
       *Resp = ShellPromptResponseMax;\r
       while (*Resp == ShellPromptResponseMax) {\r
+        if (ShellGetExecutionBreakFlag()) {\r
+          Status = EFI_ABORTED;\r
+          break;\r
+        }\r
         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
         if (Type == ShellPromptResponseTypeEnterContinue) {\r
           Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-          ASSERT_EFI_ERROR(Status);\r
+          if (EFI_ERROR(Status)) {\r
+            break;\r
+          }\r
           ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
           if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
             *Resp = ShellPromptResponseContinue;\r
@@ -3359,9 +3422,15 @@ ShellPromptForResponse (
       //\r
       *Resp = ShellPromptResponseMax;\r
       while (*Resp == ShellPromptResponseMax) {\r
+        if (ShellGetExecutionBreakFlag()) {\r
+          Status = EFI_ABORTED;\r
+          break;\r
+        }\r
         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-        ASSERT_EFI_ERROR(Status);\r
+        if (EFI_ERROR(Status)) {\r
+          break;\r
+        }\r
         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
         switch (Key.UnicodeChar) {\r
           case L'Y':\r
@@ -3380,9 +3449,15 @@ ShellPromptForResponse (
         ShellPrintEx(-1, -1, L"%s", Prompt);\r
       }\r
       while(1) {\r
+        if (ShellGetExecutionBreakFlag()) {\r
+          Status = EFI_ABORTED;\r
+          break;\r
+        }\r
         gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
         Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
-        ASSERT_EFI_ERROR(Status);\r
+        if (EFI_ERROR(Status)) {\r
+          break;\r
+        }\r
         ShellPrintEx(-1, -1, L"%c", Key.UnicodeChar);\r
         if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
           break;\r
@@ -3393,6 +3468,7 @@ ShellPromptForResponse (
       break;\r
     //\r
     // This is the location to add new prompt types.\r
+    // If your new type loops remember to add ExecutionBreak support.\r
     //\r
     default:\r
       ASSERT(FALSE);\r