Revision: 17088
          http://sourceforge.net/p/edk2/code/17088
Author:   vanjeff
Date:     2015-04-01 07:19:31 +0000 (Wed, 01 Apr 2015)
Log Message:
-----------
ShellPkg: Refactor quote and escape search to use new function.

ShellPkg: Add quotes around NSH index argument replacement.

(Sync part of patches r16682 and r16699 from main trunk.)

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jaben Carsey <[email protected]>
Signed-off-by: Joe Peterson <[email protected]>
Reviewed-by: Shumin Qiu <[email protected]>
Reviewed-by: Joe Peterson <[email protected]>
Reviewed-by: Tapan Shah <[email protected]>

Revision Links:
--------------
    http://sourceforge.net/p/edk2/code/16682
    http://sourceforge.net/p/edk2/code/16699

Modified Paths:
--------------
    branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.c
    branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.h
    branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.c
    branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.h

Modified: branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.c
===================================================================
--- branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.c     2015-04-01 
04:56:00 UTC (rev 17087)
+++ branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.c     2015-04-01 
07:19:31 UTC (rev 17088)
@@ -1,7 +1,7 @@
 /** @file
   This is THE shell (application)
 
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
   (C) Copyright 2013-2014, Hewlett-Packard Development Company, L.P.
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
@@ -101,30 +101,92 @@
 }
 
 /**
-  Find a command line contains a split operation
+  Parse for the next instance of one string within another string. Can 
optionally make sure that 
+  the string was not escaped (^ character) per the shell specification.
 
-  @param[in] CmdLine      The command line to parse.
-
-  @retval                 A pointer to the | character in CmdLine or NULL if 
not present.
+  @param[in] SourceString             The string to search within
+  @param[in] FindString               The string to look for
+  @param[in] CheckForEscapeCharacter  TRUE to skip escaped instances of 
FinfString, otherwise will return even escaped instances
 **/
-CONST CHAR16*
+CHAR16*
 EFIAPI
-FindSplit(
-  IN CONST CHAR16 *CmdLine
+FindNextInstance(
+  IN CONST CHAR16   *SourceString,
+  IN CONST CHAR16   *FindString,
+  IN CONST BOOLEAN  CheckForEscapeCharacter
   )
 {
-  CONST CHAR16 *TempSpot;
-  TempSpot = NULL;
-  if (StrStr(CmdLine, L"|") != NULL) {
-    for (TempSpot = CmdLine ; TempSpot != NULL && *TempSpot != CHAR_NULL ; 
TempSpot++) {
-      if (*TempSpot == L'^' && *(TempSpot+1) == L'|') {
-        TempSpot++;
-      } else if (*TempSpot == L'|') {
-        break;
+  CHAR16 *Temp;
+  if (SourceString == NULL) {
+    return (NULL);
+  }
+  Temp = StrStr(SourceString, FindString);
+
+  //
+  // If nothing found, or we dont care about escape characters
+  //
+  if (Temp == NULL || !CheckForEscapeCharacter) {
+    return (Temp);
+  }
+
+  //
+  // If we found an escaped character, try again on the remainder of the string
+  //
+  if ((Temp > (SourceString)) && *(Temp-1) == L'^') {
+    return FindNextInstance(Temp+1, FindString, CheckForEscapeCharacter);
+  }
+
+  //
+  // we found the right character
+  //
+  return (Temp);
+}
+
+/**
+  Check whether the string between a pair of % is a valid envifronment 
variable name.
+
+  @param[in] BeginPercent       pointer to the first percent.
+  @param[in] EndPercent          pointer to the last percent.
+
+  @retval TRUE                          is a valid environment variable name.
+  @retval FALSE                         is NOT a valid environment variable 
name.
+**/
+BOOLEAN
+IsValidEnvironmentVariableName(
+  IN CONST CHAR16     *BeginPercent,
+  IN CONST CHAR16     *EndPercent
+  )
+{
+  CONST CHAR16    *Walker;
+  
+  Walker = NULL;
+
+  ASSERT (BeginPercent != NULL);
+  ASSERT (EndPercent != NULL);
+  ASSERT (BeginPercent < EndPercent);
+  
+  if ((BeginPercent + 1) == EndPercent) {
+    return FALSE;
+  }
+
+  for (Walker = BeginPercent + 1; Walker < EndPercent; Walker++) {
+    if (
+        (*Walker >= L'0' && *Walker <= L'9') ||
+        (*Walker >= L'A' && *Walker <= L'Z') ||
+        (*Walker >= L'a' && *Walker <= L'z') ||
+        (*Walker == L'_')
+      ) {
+      if (Walker == BeginPercent + 1 && (*Walker >= L'0' && *Walker <= L'9')) {
+        return FALSE;
+      } else {
+        continue;
       }
+    } else {
+      return FALSE;
     }
   }
-  return (TempSpot);
+
+  return TRUE;
 }
 
 /**
@@ -142,7 +204,39 @@
   )
 {
   CONST CHAR16 *TempSpot;
-  TempSpot = FindSplit(CmdLine);
+  CONST CHAR16 *FirstQuote;
+  CONST CHAR16 *SecondQuote;
+
+  FirstQuote    = FindNextInstance (CmdLine, L"\"", TRUE);
+  SecondQuote   = NULL;
+  TempSpot      = FindFirstCharacter(CmdLine, L"|", L'^');
+
+  if (FirstQuote == NULL    || 
+      TempSpot == NULL      || 
+      TempSpot == CHAR_NULL || 
+      FirstQuote > TempSpot
+      ) {
+    return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));
+  }
+
+  while ((TempSpot != NULL) && (*TempSpot != CHAR_NULL)) {
+    if (FirstQuote == NULL || FirstQuote > TempSpot) {
+      break;
+    }    
+    SecondQuote = FindNextInstance (FirstQuote + 1, L"\"", TRUE);
+    if (SecondQuote == NULL) {
+      break;
+    }
+    if (SecondQuote < TempSpot) {
+      FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);
+      continue;
+    } else {
+      FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);
+      TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^');
+      continue;
+    } 
+  }
+  
   return (BOOLEAN) ((TempSpot != NULL) && (*TempSpot != CHAR_NULL));
 }
 
@@ -1233,48 +1327,6 @@
 }
 
 /**
-  Parse for the next instance of one string within another string. Can 
optionally make sure that 
-  the string was not escaped (^ character) per the shell specification.
-
-  @param[in] SourceString             The string to search within
-  @param[in] FindString               The string to look for
-  @param[in] CheckForEscapeCharacter  TRUE to skip escaped instances of 
FinfString, otherwise will return even escaped instances
-**/
-CHAR16*
-EFIAPI
-FindNextInstance(
-  IN CONST CHAR16   *SourceString,
-  IN CONST CHAR16   *FindString,
-  IN CONST BOOLEAN  CheckForEscapeCharacter
-  )
-{
-  CHAR16 *Temp;
-  if (SourceString == NULL) {
-    return (NULL);
-  }
-  Temp = StrStr(SourceString, FindString);
-
-  //
-  // If nothing found, or we dont care about escape characters
-  //
-  if (Temp == NULL || !CheckForEscapeCharacter) {
-    return (Temp);
-  }
-
-  //
-  // If we found an escaped character, try again on the remainder of the string
-  //
-  if ((Temp > (SourceString)) && *(Temp-1) == L'^') {
-    return FindNextInstance(Temp+1, FindString, CheckForEscapeCharacter);
-  }
-
-  //
-  // we found the right character
-  //
-  return (Temp);
-}
-
-/**
   This function will eliminate unreplaced (and therefore non-found) 
environment variables.
 
   @param[in,out] CmdLine   The command line to update.
@@ -1302,8 +1354,8 @@
       break;
     }
 
-    if (FirstQuote < FirstPercent) {
-      SecondQuote = FirstQuote!= NULL?FindNextInstance(FirstQuote+1, L"\"", 
TRUE):NULL;
+    if (FirstQuote!= NULL && FirstQuote < FirstPercent) {
+      SecondQuote = FindNextInstance(FirstQuote+1, L"\"", TRUE);
       //
       // Quote is first found
       //
@@ -1321,19 +1373,21 @@
       }
       continue;
     }
-    ASSERT(FirstPercent < FirstQuote);
-    if (SecondPercent < FirstQuote) {
-      FirstPercent[0] = L'\"';
-      SecondPercent[0] = L'\"';
-
-      //
-      // We need to remove from FirstPercent to SecondPercent
-      //
-      CopyMem(FirstPercent + 1, SecondPercent, StrSize(SecondPercent));
-      CurrentLocator = FirstPercent + 2;
+    
+    if (FirstQuote == NULL || SecondPercent < FirstQuote) {
+      if (IsValidEnvironmentVariableName(FirstPercent, SecondPercent)) {
+        //
+        // We need to remove from FirstPercent to SecondPercent
+        //
+        CopyMem(FirstPercent, SecondPercent + 1, StrSize(SecondPercent + 1));
+        //
+        // dont need to update the locator.  both % characters are gone.
+        //
+      } else {
+        CurrentLocator = SecondPercent + 1;
+      }
       continue;
     }
-    ASSERT(FirstQuote < SecondPercent);
     CurrentLocator = FirstQuote;
   }
   return (EFI_SUCCESS);
@@ -1448,14 +1502,14 @@
     ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, 
AliasListNode->Alias, AliasListNode->CommandString, TRUE, FALSE);
     StrnCpy(NewCommandLine1, NewCommandLine2, NewSize/sizeof(CHAR16)-1);
     }
-
-    //
-    // Remove non-existant environment variables in scripts only
-    //
-    StripUnreplacedEnvironmentVariables(NewCommandLine1);
   }
 
   //
+  // Remove non-existant environment variables
+  //
+  StripUnreplacedEnvironmentVariables(NewCommandLine1);
+
+  //
   // Now cleanup any straggler intentionally ignored "%" characters
   //
   ShellCopySearchAndReplace(NewCommandLine1, NewCommandLine2, NewSize, L"^%", 
L"%", TRUE, FALSE);
@@ -1789,12 +1843,12 @@
       return (EFI_OUT_OF_RESOURCES);
     }
     TempWalker = (CHAR16*)Temp;
-    GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine));
-
-    if (GetOperationType(FirstParameter) == Unknown_Invalid) {
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), 
ShellInfoObject.HiiHandle, FirstParameter);
-      SetLastError(SHELL_NOT_FOUND);
-      Status = EFI_NOT_FOUND;
+    if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, 
StrSize(CmdLine)))) {
+      if (GetOperationType(FirstParameter) == Unknown_Invalid) {
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), 
ShellInfoObject.HiiHandle, FirstParameter);
+        SetLastError(SHELL_NOT_FOUND);
+        Status = EFI_NOT_FOUND;
+      }
     }
   }
 
@@ -1838,7 +1892,7 @@
   //
   // recurse to verify the next item
   //
-  TempSpot = FindSplit(CmdLine)+1;
+  TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1;
   return (VerifySplit(TempSpot));
 }
 
@@ -1949,24 +2003,25 @@
   Walker = *CmdLine;
   while(Walker != NULL && *Walker != CHAR_NULL) {
     LastWalker = Walker;
-    GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine));
-    if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {
-      LastWalker[0] = L' ';
-      LastWalker[1] = L' ';
-      NewCommandLine = AllocateZeroPool(StrSize(L"help ") + StrSize(*CmdLine));
-      if (NewCommandLine == NULL) {
-        Status = EFI_OUT_OF_RESOURCES;
+    if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, 
StrSize(*CmdLine)))) {
+      if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {
+        LastWalker[0] = L' ';
+        LastWalker[1] = L' ';
+        NewCommandLine = AllocateZeroPool(StrSize(L"help ") + 
StrSize(*CmdLine));
+        if (NewCommandLine == NULL) {
+          Status = EFI_OUT_OF_RESOURCES;
+          break;
+        }
+
+        //
+        // We know the space is sufficient since we just calculated it.
+        //
+        StrnCpy(NewCommandLine, L"help ", 5);
+        StrnCat(NewCommandLine, *CmdLine, StrLen(*CmdLine));
+        SHELL_FREE_NON_NULL(*CmdLine);
+        *CmdLine = NewCommandLine;
         break;
       }
-
-      //
-      // We know the space is sufficient since we just calculated it.
-      //
-      StrnCpy(NewCommandLine, L"help ", 5);
-      StrnCat(NewCommandLine, *CmdLine, StrLen(*CmdLine));
-      SHELL_FREE_NON_NULL(*CmdLine);
-      *CmdLine = NewCommandLine;
-      break;
     }
   }
 
@@ -2418,27 +2473,30 @@
     return (EFI_OUT_OF_RESOURCES);
   }
   TempWalker = CleanOriginal;
-  GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal));
-
-  //
-  // Depending on the first parameter we change the behavior
-  //
-  switch (Type = GetOperationType(FirstParameter)) {
-    case   File_Sys_Change:
-      Status = ChangeMappedDrive (FirstParameter);
-      break;
-    case   Internal_Command:
-    case   Script_File_Name:
-    case   Efi_Application:
-      Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, 
ShellInfoObject.NewShellParametersProtocol);
-      break;
-    default:
-      //
-      // Whatever was typed, it was invalid.
-      //
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), 
ShellInfoObject.HiiHandle, FirstParameter);
-      SetLastError(SHELL_NOT_FOUND);
-      break;
+  if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, 
StrSize(CleanOriginal)))) {
+    //
+    // Depending on the first parameter we change the behavior
+    //
+    switch (Type = GetOperationType(FirstParameter)) {
+      case   File_Sys_Change:
+        Status = ChangeMappedDrive (FirstParameter);
+        break;
+      case   Internal_Command:
+      case   Script_File_Name:
+      case   Efi_Application:
+        Status = SetupAndRunCommandOrFile(Type, CleanOriginal, FirstParameter, 
ShellInfoObject.NewShellParametersProtocol);
+        break;
+      default:
+        //
+        // Whatever was typed, it was invalid.
+        //
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), 
ShellInfoObject.HiiHandle, FirstParameter);
+        SetLastError(SHELL_NOT_FOUND);
+        break;
+    }
+  } else {
+    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), 
ShellInfoObject.HiiHandle, FirstParameter);
+    SetLastError(SHELL_NOT_FOUND);
   }
  
   SHELL_FREE_NON_NULL(CleanOriginal);
@@ -2631,34 +2689,34 @@
       if (NewScriptFile->Argv != NULL) {
         switch (NewScriptFile->Argc) {
           default:
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%9", NewScriptFile->Argv[9], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 9:
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%8", NewScriptFile->Argv[8], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 8:
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%7", NewScriptFile->Argv[7], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 7:
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%6", NewScriptFile->Argv[6], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 6:
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%5", NewScriptFile->Argv[5], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 5:
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%4", NewScriptFile->Argv[4], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 4:
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%3", NewScriptFile->Argv[3], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 3:
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%2", NewScriptFile->Argv[2], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 2:
-            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine2,  CommandLine, 
PcdGet16 (PcdShellPrintBufferSize), L"%1", NewScriptFile->Argv[1], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
           case 1:
-            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, 
FALSE);
+            Status = ShellCopySearchAndReplace(CommandLine,  CommandLine2, 
PcdGet16 (PcdShellPrintBufferSize), L"%0", NewScriptFile->Argv[0], FALSE, TRUE);
             ASSERT_EFI_ERROR(Status);
             break;
           case 0:
@@ -2836,3 +2894,38 @@
 
   return (Status);
 }
+
+/**
+  Return the pointer to the first occurance of any character from a list of 
characters
+
+  @param[in] String           the string to parse
+  @param[in] CharacterList    the list of character to look for
+  @param[in] EscapeCharacter  An escape character to skip
+
+  @return the location of the first character in the string
+  @retval CHAR_NULL no instance of any character in CharacterList was found in 
String
+**/
+CONST CHAR16*
+EFIAPI
+FindFirstCharacter(
+  IN CONST CHAR16 *String,
+  IN CONST CHAR16 *CharacterList,
+  IN CONST CHAR16 EscapeCharacter
+  )
+{
+  UINT32 WalkChar;
+  UINT32 WalkStr;
+
+  for (WalkStr = 0; WalkStr < StrLen(String); WalkStr++) {
+    if (String[WalkStr] == EscapeCharacter) {
+      WalkStr++;
+      continue;
+    }
+    for (WalkChar = 0; WalkChar < StrLen(CharacterList); WalkChar++) {
+      if (String[WalkStr] == CharacterList[WalkChar]) {
+        return (&String[WalkStr]);
+      }
+    }
+  }
+  return (String + StrLen(String));
+}
\ No newline at end of file

Modified: branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.h
===================================================================
--- branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.h     2015-04-01 
04:56:00 UTC (rev 17087)
+++ branches/UDK2014.SP1/ShellPkg/Application/Shell/Shell.h     2015-04-01 
07:19:31 UTC (rev 17088)
@@ -2,7 +2,7 @@
   function definitions for internal to shell functions.
 
   (C) Copyright 2014, Hewlett-Packard Development Company, L.P.
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -343,6 +343,23 @@
   IN EFI_SHELL_PARAMETERS_PROTOCOL  *ParamProtocol
   );
 
+/**
+  Return the pointer to the first occurance of any character from a list of 
characters
 
+  @param[in] String           the string to parse
+  @param[in] CharacterList    the list of character to look for
+  @param[in] EscapeCharacter  An escape character to skip
+
+  @return the location of the first character in the string
+  @retval CHAR_NULL no instance of any character in CharacterList was found in 
String
+**/
+CONST CHAR16*
+EFIAPI
+FindFirstCharacter(
+  IN CONST CHAR16 *String,
+  IN CONST CHAR16 *CharacterList,
+  IN CONST CHAR16 EscapeCharacter
+  );
+
 #endif //_SHELL_INTERNAL_HEADER_
 

Modified: 
branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.c
===================================================================
--- branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.c   
2015-04-01 04:56:00 UTC (rev 17087)
+++ branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.c   
2015-04-01 07:19:31 UTC (rev 17088)
@@ -4,7 +4,7 @@
 
   Copyright (C) 2014, Red Hat, Inc.
   Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
-  Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD 
License
   which accompanies this distribution.  The full text of the license may be 
found at
@@ -18,8 +18,51 @@
 #include "Shell.h"
 
 /**
-  return the next parameter from a command line string;
+  Return the next parameter's end from a command line string.
 
+  @param[in] String        the string to parse
+**/
+CONST CHAR16*
+EFIAPI
+FindEndOfParameter(
+  IN CONST CHAR16 *String
+  )
+{
+  CONST CHAR16 *First;
+  CONST CHAR16 *CloseQuote;
+
+  First = FindFirstCharacter(String, L" \"", L'^');
+
+  //
+  // nothing, all one parameter remaining
+  //
+  if (*First == CHAR_NULL) {
+    return (First);
+  }
+
+  //
+  // If space before a quote (or neither found, i.e. both CHAR_NULL),
+  // then that's the end.
+  //
+  if (*First == L' ') {
+    return (First);
+  }
+
+  CloseQuote = FindFirstCharacter (First+1, L"\"", L'^');
+
+  //
+  // We did not find a terminator...
+  //
+  if (*CloseQuote == CHAR_NULL) {
+    return (NULL);
+  }
+
+  return (FindEndOfParameter (CloseQuote+1));
+}
+
+/**
+  Return the next parameter from a command line string.
+
   This function moves the next parameter from Walker into TempParameter and 
moves
   Walker up past that parameter for recursive calling.  When the final 
parameter
   is moved *Walker will be set to NULL;
@@ -27,12 +70,17 @@
   Temp Parameter must be large enough to hold the parameter before calling this
   function.
 
+  This will also remove all remaining ^ characters after processing.
+
   @param[in, out] Walker        pointer to string of command line.  Adjusted to
                                 reminaing command line on return
   @param[in, out] TempParameter pointer to string of command line item 
extracted.
   @param[in]      Length        buffer size of TempParameter.
+
+  @return   EFI_INALID_PARAMETER  A required parameter was NULL or pointed to 
a NULL or empty string.
+  @return   EFI_NOT_FOUND         A closing " could not be found on the 
specified string
 **/
-VOID
+EFI_STATUS
 EFIAPI
 GetNextParameter(
   IN OUT CHAR16   **Walker,
@@ -40,14 +88,17 @@
   IN CONST UINTN  Length
   )
 {
-  CHAR16 *NextDelim;
-  CHAR16 *TempLoc;
+  CONST CHAR16 *NextDelim;
 
-  ASSERT(Walker           != NULL);
-  ASSERT(*Walker          != NULL);
-  ASSERT(TempParameter    != NULL);
-  ASSERT(*TempParameter   != NULL);
+  if (Walker           == NULL
+    ||*Walker          == NULL
+    ||TempParameter    == NULL
+    ||*TempParameter   == NULL
+    ){
+    return (EFI_INVALID_PARAMETER);
+  }
 
+
   //
   // make sure we dont have any leading spaces
   //
@@ -59,81 +110,60 @@
   // make sure we still have some params now...
   //
   if (StrLen(*Walker) == 0) {
-    ASSERT((*Walker)[0] == CHAR_NULL);
-    *Walker = NULL;
-    return;
+DEBUG_CODE_BEGIN();
+    *Walker        = NULL;
+DEBUG_CODE_END();
+    return (EFI_INVALID_PARAMETER);
   }
 
+  NextDelim = FindEndOfParameter(*Walker);
+
+  if (NextDelim == NULL){
+DEBUG_CODE_BEGIN();
+    *Walker        = NULL;
+DEBUG_CODE_END();
+    return (EFI_NOT_FOUND);
+  }
+
+  StrnCpy(*TempParameter, (*Walker), NextDelim - *Walker);
+
   //
-  // we have a quoted parameter
-  // could be the last parameter, but SHOULD have a trailing quote
+  // Add a CHAR_NULL if we didnt get one via the copy
   //
-  if ((*Walker)[0] == L'\"') {
-    NextDelim = NULL;
-    for (TempLoc = *Walker + 1 ; TempLoc != NULL && *TempLoc != CHAR_NULL ; 
TempLoc++) {
-      if (*TempLoc == L'^' && *(TempLoc+1) == L'\"') {
-        TempLoc++;
-      } else if (*TempLoc == L'\"') {
-        NextDelim = TempLoc;
-        break;
-      }
-    }
+  if (*NextDelim != CHAR_NULL) {
+    (*TempParameter)[NextDelim - *Walker] = CHAR_NULL;
+  }
 
-    if (NextDelim - ((*Walker)+1) == 0) {
+  //
+  // Update Walker for the next iteration through the function
+  //
+  *Walker = (CHAR16*)NextDelim;
+
+  //
+  // Remove any non-escaped quotes in the string
+  // Remove any remaining escape characters in the string
+  //
+  for (NextDelim = FindFirstCharacter(*TempParameter, L"\"^", CHAR_NULL) 
+    ; *NextDelim != CHAR_NULL 
+    ; NextDelim = FindFirstCharacter(NextDelim, L"\"^", CHAR_NULL)
+    ) {
+    if (*NextDelim == L'^') {
+
       //
-      // found ""
+      // eliminate the escape ^
       //
-      *(*TempParameter) = CHAR_NULL;
-      *Walker = NextDelim + 1;
-    } else if (NextDelim != NULL) {
+      CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
+      NextDelim++;
+    } else if (*NextDelim == L'\"') {
 
       //
-      // Copy ensuring that both quotes are left in place.
+      // eliminate the unescaped quote
       //
-      StrnCpy(*TempParameter, (*Walker), NextDelim - *Walker + 1);
-      *Walker = NextDelim + 1;
-    } else {
-      //
-      // last one... someone forgot the training quote!
-      //
-      StrnCpy(*TempParameter, *Walker, Length/sizeof(CHAR16) - 1);
-      *Walker = NULL;
+      CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
     }
-    for (TempLoc = *TempParameter ; TempLoc != NULL && *TempLoc != CHAR_NULL ; 
TempLoc++) {
-      if (*TempLoc == L'^' && *(TempLoc+1) == L'\"') {
-        CopyMem(TempLoc, TempLoc+1, StrSize(TempLoc) - sizeof(TempLoc[0]));
-      }
-    }
-  } else {
-    //
-    // we have a regular parameter (no quote) OR
-    // we have the final parameter (no trailing space)
-    //
-    NextDelim = StrStr((*Walker), L" ");
-    if (NextDelim != NULL) {
-      StrnCpy(*TempParameter, *Walker, NextDelim - (*Walker));
-      (*TempParameter)[NextDelim - (*Walker)] = CHAR_NULL;
-      *Walker = NextDelim+1;
-    } else {
-      //
-      // last one.
-      //
-      StrnCpy(*TempParameter, *Walker, Length/sizeof(CHAR16) - 1);
-      *Walker = NULL;
-    }
-    for (NextDelim = *TempParameter ; NextDelim != NULL && *NextDelim != 
CHAR_NULL ; NextDelim++) {
-      if (*NextDelim == L'^' && *(NextDelim+1) == L'^') {
-        CopyMem(NextDelim, NextDelim+1, StrSize(NextDelim) - 
sizeof(NextDelim[0]));
-      }
-    }
-    while ((*TempParameter)[StrLen(*TempParameter)-1] == L' ') {
-      (*TempParameter)[StrLen(*TempParameter)-1] = CHAR_NULL;
-    }
-    while ((*TempParameter)[0] == L' ') {
-      CopyMem(*TempParameter, (*TempParameter)+1, StrSize(*TempParameter) - 
sizeof((*TempParameter)[0]));
-    }
   }
-  return;
+
+  return EFI_SUCCESS;
 }
 
 /**
@@ -143,6 +173,9 @@
   parameters for inclusion in EFI_SHELL_PARAMETERS_PROTOCOL.  this supports 
space
   delimited and quote surrounded parameter definition.
 
+  All special character processing (alias, environment variable, redirection, 
+  etc... must be complete before calling this API.
+
   @param[in] CommandLine         String of command line to parse
   @param[in, out] Argv           pointer to array of strings; one for each 
parameter
   @param[in, out] Argc           pointer to number of strings in Argv array
@@ -182,9 +215,12 @@
   for ( Count = 0
       , Walker = (CHAR16*)CommandLine
       ; Walker != NULL && *Walker != CHAR_NULL
-      ; GetNextParameter(&Walker, &TempParameter, Size)
-      , Count++
-     );
+      ; Count++
+      ) {
+    if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size))) {
+      break;
+    }
+  }
 
   //
   // lets allocate the pointer array
@@ -199,7 +235,11 @@
   Walker = (CHAR16*)CommandLine;
   while(Walker != NULL && *Walker != CHAR_NULL) {
     SetMem16(TempParameter, Size, CHAR_NULL);
-    GetNextParameter(&Walker, &TempParameter, Size);
+    if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size))) {
+      SHELL_FREE_NON_NULL(TempParameter);
+      return (EFI_INVALID_PARAMETER);
+    }
+
     NewParam = AllocateCopyPool(StrSize(TempParameter), TempParameter);
     if (NewParam == NULL){
       SHELL_FREE_NON_NULL(TempParameter);

Modified: 
branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.h
===================================================================
--- branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.h   
2015-04-01 04:56:00 UTC (rev 17087)
+++ branches/UDK2014.SP1/ShellPkg/Application/Shell/ShellParametersProtocol.h   
2015-04-01 07:19:31 UTC (rev 17088)
@@ -192,8 +192,10 @@
   @param[in, out] TempParameter pointer to string of command line item 
extracted.
   @param[in]      Length        Length of (*TempParameter) in bytes
 
+  @return   EFI_INALID_PARAMETER  A required parameter was NULL or pointed to 
a NULL or empty string.
+  @return   EFI_NOT_FOUND         A closing " could not be found on the 
specified string
 **/
-VOID
+EFI_STATUS
 EFIAPI
 GetNextParameter(
   IN OUT CHAR16   **Walker,


------------------------------------------------------------------------------
Dive into the World of Parallel Programming The Go Parallel Website, sponsored
by Intel and developed in partnership with Slashdot Media, is your hub for all
things parallel software development, from weekly thought leadership blogs to
news, videos, case studies, tutorials and more. Take a look and join the 
conversation now. http://goparallel.sourceforge.net/
_______________________________________________
edk2-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-commits

Reply via email to