I do have few comments:
1. Echo.c:84
  If (OnFlag) {...}  Else if (OffFlag) {...}
  The above code can be changed to:
  If (OnFlag || OffFlag) {...}

2. Echo.c:94
  Does OriginalCmdLine contains empty spaces in the beginning?
  After I checked the code in Shell.c I then knew that the spaces were trimmed.
  Can you add assertion (make sure the beginning spaces are trimmed) here to 
make sure the behavior of Shell.c won't be changed in future?

3. UefiShellCommandLib.c: 33
  mRawCmdLine?

4. UefiShellCommandLib.c: 98
  Do we need to put "Shell" prefix to all the newly added APIs?
  FindFirstCharacter -> ShellFindFirstCharacter
  FindEndOfParameter -> ShellFindEndOfParameter
  GetNextParameter -> ShellGetNextParameter

5. FindEndOfParameter is really needed to expose in UefiShellCommandLib.h?
  I don't find any references to this function in Shell.c, nor in 
ShellParametersProtocol.c.
  Can it be an internal function inside UefiShellCommandLib.c?

6. UefiShellCommandLib.c: 1868
  ShellGetOriginalCmdLine -> ShellGetRawCmdLine?
  ShellSetOriginalCmdLine -> ShellSetRawCmdLine?

Thanks,
Ray

-----Original Message-----
From: Carsey, Jaben 
Sent: Wednesday, June 22, 2016 11:17 PM
To: Qiu, Shumin <shumin....@intel.com>; edk2-devel@lists.01.org
Cc: Ni, Ruiyu <ruiyu...@intel.com>; Carsey, Jaben <jaben.car...@intel.com>
Subject: RE: [PATCH v2] ShellPkg: Fix 'echo' cannot display the special 
characters correctly.

Very nice.  I like this much more.

Reviewed-by: Jaben Carsey <jaben.car...@intel.com>

Ray, what do you think?

-Jaben

> -----Original Message-----
> From: Qiu, Shumin
> Sent: Wednesday, June 22, 2016 1:51 AM
> To: edk2-devel@lists.01.org
> Cc: Qiu, Shumin <shumin....@intel.com>; Carsey, Jaben 
> <jaben.car...@intel.com>; Ni, Ruiyu <ruiyu...@intel.com>
> Subject: [PATCH v2] ShellPkg: Fix 'echo' cannot display the special 
> characters correctly.
> Importance: High
> 
> Difference with previous:
> Use Shell command Lib API to get original command string.
> 
> Currently run 'echo -t' will get the result:
> echo: Unknown flag - '-t'
> The expected result is to display '-t' literally.
> This patch adds special handle for 'echo'. 'echo' will not use the 
> general parameter parsing library .
> 
> Cc: Jaben Carsey <jaben.car...@intel.com>
> Cc: Ruiyu Ni <ruiyu...@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Qiu Shumin <shumin....@intel.com>
> ---
>  ShellPkg/Application/Shell/Shell.c                 |  63 ++--
>  ShellPkg/Application/Shell/Shell.h                 |  18 --
>  .../Application/Shell/ShellParametersProtocol.c    | 156 ---------
>  .../Application/Shell/ShellParametersProtocol.h    |  29 --
>  ShellPkg/Include/Library/ShellCommandLib.h         | 120 +++++--
>  .../UefiShellCommandLib/UefiShellCommandLib.c      | 360
> +++++++++++++++++----
>  ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c | 145 ++++-----
>  .../UefiShellLevel3CommandsLib.uni                 |   1 +
>  8 files changed, 490 insertions(+), 402 deletions(-)
> 
> diff --git a/ShellPkg/Application/Shell/Shell.c
> b/ShellPkg/Application/Shell/Shell.c
> index 54ca76a..90d6903 100644
> --- a/ShellPkg/Application/Shell/Shell.c
> +++ b/ShellPkg/Application/Shell/Shell.c
> @@ -716,6 +716,7 @@ FreeResources:
>    }
> 
>    ShellFreeEnvVarList ();
> +  ShellSetOriginalCmdLine (NULL);
> 
>    if (ShellCommandGetExit()) {
>      return ((EFI_STATUS)ShellCommandGetExitCode());
> @@ -2578,6 +2579,7 @@ RunShellCommand(
>    CHAR16                    *FirstParameter;
>    CHAR16                    *TempWalker;
>    SHELL_OPERATION_TYPES     Type;
> +  CHAR16                    *OldCmdLine;
> 
>    ASSERT(CmdLine != NULL);
>    if (StrLen(CmdLine) == 0) {
> @@ -2585,11 +2587,14 @@ RunShellCommand(
>    }
> 
>    Status              = EFI_SUCCESS;
> +  FirstParameter      = NULL;
>    CleanOriginal       = NULL;
> +  OldCmdLine          = NULL;
> 
>    CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0);
>    if (CleanOriginal == NULL) {
> -    return (EFI_OUT_OF_RESOURCES);
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
>    }
> 
>    TrimSpaces(&CleanOriginal);
> @@ -2616,23 +2621,24 @@ RunShellCommand(
>    // Handle case that passed in command line is just 1 or more " " 
> characters.
>    //
>    if (StrLen (CleanOriginal) == 0) {
> -    SHELL_FREE_NON_NULL(CleanOriginal);
> -    return (EFI_SUCCESS);
> +    Status = EFI_SUCCESS;
> +    goto Done;
>    }
> 
>    Status = ProcessCommandLineToFinal(&CleanOriginal);
>    if (EFI_ERROR(Status)) {
> -    SHELL_FREE_NON_NULL(CleanOriginal);
> -    return (Status);
> +    goto Done;
>    }
> +
> +  OldCmdLine = ShellGetOriginalCmdLine();  
> + ShellSetOriginalCmdLine(CleanOriginal);
> 
>    //
>    // We don't do normal processing with a split command line (output 
> from one command input to another)
>    //
>    if (ContainsSplit(CleanOriginal)) {
>      Status = ProcessNewSplitCommandLine(CleanOriginal);
> -    SHELL_FREE_NON_NULL(CleanOriginal);
> -    return (Status);
> +    goto Done;
>    }
> 
>    //
> @@ -2640,8 +2646,8 @@ RunShellCommand(
>    //
>    FirstParameter = AllocateZeroPool(StrSize(CleanOriginal));
>    if (FirstParameter == NULL) {
> -    SHELL_FREE_NON_NULL(CleanOriginal);
> -    return (EFI_OUT_OF_RESOURCES);
> +    Status = EFI_OUT_OF_RESOURCES;
> +    goto Done;
>    }
>    TempWalker = CleanOriginal;
>    if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, 
> StrSize(CleanOriginal), TRUE))) { @@ -2669,7 +2675,10 @@ 
> RunShellCommand(
>      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), 
> ShellInfoObject.HiiHandle, FirstParameter);
>      SetLastError(SHELL_NOT_FOUND);
>    }
> -
> +
> +Done:
> +  ShellSetOriginalCmdLine(OldCmdLine);
> +  SHELL_FREE_NON_NULL(OldCmdLine);
>    SHELL_FREE_NON_NULL(CleanOriginal);
>    SHELL_FREE_NON_NULL(FirstParameter);
> 
> @@ -3109,37 +3118,3 @@ RunScriptFile (
>    return (Status);
>  }
> 
> -/**
> -  Return the pointer to the first occurrence 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));
> -}
> diff --git a/ShellPkg/Application/Shell/Shell.h
> b/ShellPkg/Application/Shell/Shell.h
> index 29b36b0..a34c91a 100644
> --- a/ShellPkg/Application/Shell/Shell.h
> +++ b/ShellPkg/Application/Shell/Shell.h
> @@ -371,24 +371,6 @@ RunScriptFile (
>    );
> 
>  /**
> -  Return the pointer to the first occurrence 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
> -  );
> -
> -/**
>    Cleans off leading and trailing spaces and tabs.
> 
>    @param[in] String pointer to the string to trim them off.
> diff --git a/ShellPkg/Application/Shell/ShellParametersProtocol.c
> b/ShellPkg/Application/Shell/ShellParametersProtocol.c
> index b3767bb..798e1d1 100644
> --- a/ShellPkg/Application/Shell/ShellParametersProtocol.c
> +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.c
> @@ -20,162 +20,6 @@
>  BOOLEAN AsciiRedirection = FALSE;
> 
>  /**
> -  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;
> -
> -  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.
> -  @param[in]      StripQuotation  if TRUE then strip the quotation marks
> surrounding
> -                                  the parameters.
> -
> -  @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
> -**/
> -EFI_STATUS
> -EFIAPI
> -GetNextParameter(
> -  IN OUT CHAR16   **Walker,
> -  IN OUT CHAR16   **TempParameter,
> -  IN CONST UINTN  Length,
> -  IN BOOLEAN      StripQuotation
> -  )
> -{
> -  CONST CHAR16 *NextDelim;
> -
> -  if (Walker           == NULL
> -    ||*Walker          == NULL
> -    ||TempParameter    == NULL
> -    ||*TempParameter   == NULL
> -    ){
> -    return (EFI_INVALID_PARAMETER);
> -  }
> -
> -
> -  //
> -  // make sure we dont have any leading spaces
> -  //
> -  while ((*Walker)[0] == L' ') {
> -      (*Walker)++;
> -  }
> -
> -  //
> -  // make sure we still have some params now...
> -  //
> -  if (StrLen(*Walker) == 0) {
> -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);
> -  }
> -
> -  StrnCpyS(*TempParameter, Length / sizeof(CHAR16), (*Walker), 
> NextDelim - *Walker);
> -
> -  //
> -  // Add a CHAR_NULL if we didnt get one via the copy
> -  //
> -  if (*NextDelim != CHAR_NULL) {
> -    (*TempParameter)[NextDelim - *Walker] = CHAR_NULL;
> -  }
> -
> -  //
> -  // 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'^') {
> -
> -      //
> -      // eliminate the escape ^
> -      //
> -      CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim +
> 1));
> -      NextDelim++;
> -    } else if (*NextDelim == L'\"') {
> -
> -      //
> -      // eliminate the unescaped quote
> -      //
> -      if (StripQuotation) {
> -        CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim +
> 1));
> -       } else{
> -        NextDelim++;
> -       }
> -    }
> -  }
> -
> -  return EFI_SUCCESS;
> -}
> -
> -/**
>    Function to populate Argc and Argv.
> 
>    This function parses the CommandLine and divides it into standard C 
> style Argc/Argv diff --git 
> a/ShellPkg/Application/Shell/ShellParametersProtocol.h
> b/ShellPkg/Application/Shell/ShellParametersProtocol.h
> index 926f362..1205d92 100644
> --- a/ShellPkg/Application/Shell/ShellParametersProtocol.h
> +++ b/ShellPkg/Application/Shell/ShellParametersProtocol.h
> @@ -190,34 +190,5 @@ ParseCommandLineToArgs(
>    IN OUT UINTN    *Argc
>    );
> 
> -/**
> -  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;
> -
> -  Temp Parameter must be large enough to hold the parameter before 
> calling this
> -  function.
> -
> -  @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          Length of (*TempParameter) in bytes
> -  @param[in]      StripQuotation  if TRUE then strip the quotation marks
> surrounding
> -                                  the parameters.
> -
> -  @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
> -**/
> -EFI_STATUS
> -EFIAPI
> -GetNextParameter(
> -  IN OUT CHAR16   **Walker,
> -  IN OUT CHAR16   **TempParameter,
> -  IN CONST UINTN  Length,
> -  IN BOOLEAN      StripQuotation
> -  );
> -
>  #endif //_SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_
> 
> diff --git a/ShellPkg/Include/Library/ShellCommandLib.h
> b/ShellPkg/Include/Library/ShellCommandLib.h
> index e3bb6e0..7bec252 100644
> --- a/ShellPkg/Include/Library/ShellCommandLib.h
> +++ b/ShellPkg/Include/Library/ShellCommandLib.h
> @@ -5,8 +5,8 @@
>    This library will not funciton if it is used for UEFI Shell 2.0 
> Applications.
> 
>    Copyright (c) 2009 - 2014, Intel Corporation. All rights 
> reserved.<BR>
> -  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
> -  (C) Copyright 2013-2014 Hewlett-Packard Development Company, 
> L.P.<BR>
> +  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
> +  (C) Copyright 2013-2014 Hewlett-Packard Development Company,
> L.P.<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 @@ -670,6 +670,29 @@ ShellFileHandleEof(
>    IN SHELL_FILE_HANDLE Handle
>    );
> 
> +/**
> +  Function to get the original CmdLine string for current command.
> +
> +  @return     A pointer to the buffer of the original command string.
> +              It's the caller's responsibility to free the buffer.
> +**/
> +CHAR16*
> +EFIAPI
> +ShellGetOriginalCmdLine(
> +  VOID
> +  );
> +
> +/**
> +  Function to store the orgignal command string into mOriginalCmdLine.
> +
> +  @param[in] CmdLine     the command line string to store.
> +**/
> +VOID
> +EFIAPI
> +ShellSetOriginalCmdLine(
> +  IN CONST CHAR16     *CmdLine
> +  );
> +
>  typedef struct {
>    LIST_ENTRY    Link;
>    void          *Buffer;
> @@ -702,21 +725,80 @@ DumpHex (
>    IN VOID         *UserData
>    );
> 
> -/**
> -  Dump HEX data into buffer.
> -
> -  @param[in] Buffer     HEX data to be dumped in Buffer.
> -  @param[in] Indent     How many spaces to indent the output.
> -  @param[in] Offset     The offset of the printing.
> -  @param[in] DataSize   The size in bytes of UserData.
> -  @param[in] UserData   The data to print out.
> -**/
> -CHAR16*
> -CatSDumpHex (
> -  IN CHAR16  *Buffer,
> -  IN UINTN   Indent,
> -  IN UINTN   Offset,
> -  IN UINTN   DataSize,
> -  IN VOID    *UserData
> -  );
> +/**
> +  Dump HEX data into buffer.
> +
> +  @param[in] Buffer     HEX data to be dumped in Buffer.
> +  @param[in] Indent     How many spaces to indent the output.
> +  @param[in] Offset     The offset of the printing.
> +  @param[in] DataSize   The size in bytes of UserData.
> +  @param[in] UserData   The data to print out.
> +**/
> +CHAR16*
> +CatSDumpHex (
> +  IN CHAR16  *Buffer,
> +  IN UINTN   Indent,
> +  IN UINTN   Offset,
> +  IN UINTN   DataSize,
> +  IN VOID    *UserData
> +  );
> +
> +/**
> +  Return the pointer to the first occurrence 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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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;
> +
> +  Temp Parameter must be large enough to hold the parameter before
> calling this
> +  function.
> +
> +  @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          Length of (*TempParameter) in bytes
> +  @param[in]      StripQuotation  if TRUE then strip the quotation marks
> surrounding
> +                                  the parameters.
> +
> +  @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
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextParameter(
> +  IN OUT CHAR16   **Walker,
> +  IN OUT CHAR16   **TempParameter,
> +  IN CONST UINTN  Length,
> +  IN BOOLEAN      StripQuotation
> +  );
> +
>  #endif //_SHELL_COMMAND_LIB_
> diff --git 
> a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> index 48e4d4a..e3c436a 100644
> --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c
> @@ -2,9 +2,9 @@
>    Provides interface to shell internal functions for shell commands.
> 
>    Copyright (c) 2009 - 2014, Intel Corporation. All rights 
> reserved.<BR>
> -  (C) Copyright 2013-2015 Hewlett-Packard Development Company, 
> L.P.<BR>
> -  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
> -
> +  (C) Copyright 2013-2015 Hewlett-Packard Development Company,
> L.P.<BR>
> +  (C) Copyright 2016 Hewlett Packard Enterprise Development LP<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
> @@ -30,6 +30,7 @@ STATIC UINTN                              mProfileListSize;
>  STATIC UINTN                              mFsMaxCount = 0;
>  STATIC UINTN                              mBlkMaxCount = 0;
>  STATIC BUFFER_LIST                        mFileHandleList;
> +STATIC CHAR16                             *mOriginalCmdLine = NULL;
> 
>  STATIC CONST CHAR8 Hex[] = {
>    '0',
> @@ -83,6 +84,199 @@ CommandInit(
>  }
> 
>  /**
> +  Return the pointer to the first occurrence 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));
> +}
> +
> +
> +/**
> +  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;
> +
> +  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.
> +  @param[in]      StripQuotation  if TRUE then strip the quotation marks
> surrounding
> +                                  the parameters.
> +
> +  @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
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetNextParameter(
> +  IN OUT CHAR16   **Walker,
> +  IN OUT CHAR16   **TempParameter,
> +  IN CONST UINTN  Length,
> +  IN BOOLEAN      StripQuotation
> +  )
> +{
> +  CONST CHAR16 *NextDelim;
> +
> +  if (Walker           == NULL
> +    ||*Walker          == NULL
> +    ||TempParameter    == NULL
> +    ||*TempParameter   == NULL
> +    ){
> +    return (EFI_INVALID_PARAMETER);
> +  }
> +
> +
> +  //
> +  // make sure we dont have any leading spaces  //  while 
> + ((*Walker)[0] == L' ') {
> +      (*Walker)++;
> +  }
> +
> +  //
> +  // make sure we still have some params now...
> +  //
> +  if (StrLen(*Walker) == 0) {
> +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);
> +  }
> +
> +  StrnCpyS(*TempParameter, Length / sizeof(CHAR16), (*Walker),
> NextDelim - *Walker);
> +
> +  //
> +  // Add a CHAR_NULL if we didnt get one via the copy  //  if 
> + (*NextDelim != CHAR_NULL) {
> +    (*TempParameter)[NextDelim - *Walker] = CHAR_NULL;  }
> +
> +  //
> +  // 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'^') {
> +
> +      //
> +      // eliminate the escape ^
> +      //
> +      CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize (NextDelim 
> + +
> 1));
> +      NextDelim++;
> +    } else if (*NextDelim == L'\"') {
> +
> +      //
> +      // eliminate the unescaped quote
> +      //
> +      if (StripQuotation) {
> +        CopyMem ((CHAR16*)NextDelim, NextDelim + 1, StrSize 
> + (NextDelim +
> 1));
> +       } else{
> +        NextDelim++;
> +       }
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +
> +/**
>    Constructor for the Shell Command library.
> 
>    Initialize the library and determine if the underlying is a UEFI 
> Shell 2.0 or an EFI shell.
> @@ -1664,6 +1858,51 @@ ShellFileHandleEof(  }
> 
>  /**
> +  Function to get the original CmdLine string for current command.
> +
> +  @return     A pointer to the buffer of the original command string.
> +              It's the caller's responsibility to free the buffer.
> +**/
> +CHAR16*
> +EFIAPI
> +ShellGetOriginalCmdLine(
> +  VOID
> +  )
> +{
> +  CHAR16     *RetCmdLine;
> +
> +  if (mOriginalCmdLine == NULL) {
> +    return NULL;
> +  } else {
> +    RetCmdLine = AllocateCopyPool(StrSize(mOriginalCmdLine),
> mOriginalCmdLine);
> +    ASSERT (RetCmdLine != NULL);
> +
> +    return RetCmdLine;
> +  }
> +}
> +
> +/**
> +  Function to store the orgignal command string into mOriginalCmdLine.
> +
> +  @param[in] CmdLine     the command line string to store.
> +**/
> +VOID
> +EFIAPI
> +ShellSetOriginalCmdLine(
> +  IN CONST CHAR16     *CmdLine
> +  )
> +{
> +  SHELL_FREE_NON_NULL(mOriginalCmdLine);
> +
> +  if (CmdLine != NULL) {
> +    mOriginalCmdLine = AllocateCopyPool (StrSize(CmdLine), CmdLine);
> +    ASSERT(mOriginalCmdLine);
> +  }
> +
> +}
> +
> +
> +/**
>    Frees any BUFFER_LIST defined type.
> 
>    @param[in] List     The BUFFER_LIST object to free.
> @@ -1744,60 +1983,61 @@ DumpHex (
>      DataSize -= Size;
>    }
>  }
> -
> -/**
> -  Dump HEX data into buffer.
> -
> -  @param[in] Buffer     HEX data to be dumped in Buffer.
> -  @param[in] Indent     How many spaces to indent the output.
> -  @param[in] Offset     The offset of the printing.
> -  @param[in] DataSize   The size in bytes of UserData.
> -  @param[in] UserData   The data to print out.
> -**/
> -CHAR16*
> -CatSDumpHex (
> -  IN CHAR16  *Buffer,
> -  IN UINTN   Indent,
> -  IN UINTN   Offset,
> -  IN UINTN   DataSize,
> -  IN VOID    *UserData
> -  )
> -{
> -  UINT8   *Data;
> -  UINT8   TempByte;
> -  UINTN   Size;
> -  UINTN   Index;
> -  CHAR8   Val[50];
> -  CHAR8   Str[20];
> -  CHAR16  *RetVal;
> -  CHAR16  *TempRetVal;
> -
> -  Data = UserData;
> -  RetVal = Buffer;
> -  while (DataSize != 0) {
> -    Size = 16;
> -    if (Size > DataSize) {
> -      Size = DataSize;
> -    }
> -
> -    for (Index = 0; Index < Size; Index += 1) {
> -      TempByte            = Data[Index];
> -      Val[Index * 3 + 0]  = Hex[TempByte >> 4];
> -      Val[Index * 3 + 1]  = Hex[TempByte & 0xF];
> -      Val[Index * 3 + 2]  = (CHAR8) ((Index == 7) ? '-' : ' ');
> -      Str[Index]          = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? 
> '.' :
> TempByte);
> -    }
> -
> -    Val[Index * 3]  = 0;
> -    Str[Index]      = 0;
> -    TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", Indent,
> "", Offset, Val, Str);
> -    SHELL_FREE_NON_NULL (RetVal);
> -    RetVal = TempRetVal;
> -
> -    Data += Size;
> -    Offset += Size;
> -    DataSize -= Size;
> -  }
> -
> -  return RetVal;
> -}
> +
> +/**
> +  Dump HEX data into buffer.
> +
> +  @param[in] Buffer     HEX data to be dumped in Buffer.
> +  @param[in] Indent     How many spaces to indent the output.
> +  @param[in] Offset     The offset of the printing.
> +  @param[in] DataSize   The size in bytes of UserData.
> +  @param[in] UserData   The data to print out.
> +**/
> +CHAR16*
> +CatSDumpHex (
> +  IN CHAR16  *Buffer,
> +  IN UINTN   Indent,
> +  IN UINTN   Offset,
> +  IN UINTN   DataSize,
> +  IN VOID    *UserData
> +  )
> +{
> +  UINT8   *Data;
> +  UINT8   TempByte;
> +  UINTN   Size;
> +  UINTN   Index;
> +  CHAR8   Val[50];
> +  CHAR8   Str[20];
> +  CHAR16  *RetVal;
> +  CHAR16  *TempRetVal;
> +
> +  Data = UserData;
> +  RetVal = Buffer;
> +  while (DataSize != 0) {
> +    Size = 16;
> +    if (Size > DataSize) {
> +      Size = DataSize;
> +    }
> +
> +    for (Index = 0; Index < Size; Index += 1) {
> +      TempByte            = Data[Index];
> +      Val[Index * 3 + 0]  = Hex[TempByte >> 4];
> +      Val[Index * 3 + 1]  = Hex[TempByte & 0xF];
> +      Val[Index * 3 + 2]  = (CHAR8) ((Index == 7) ? '-' : ' ');
> +      Str[Index]          = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? 
> '.' :
> TempByte);
> +    }
> +
> +    Val[Index * 3]  = 0;
> +    Str[Index]      = 0;
> +    TempRetVal = CatSPrint (RetVal, L"%*a%08X: %-48a *%a*\r\n", 
> + Indent,
> "", Offset, Val, Str);
> +    SHELL_FREE_NON_NULL (RetVal);
> +    RetVal = TempRetVal;
> +
> +    Data += Size;
> +    Offset += Size;
> +    DataSize -= Size;
> +  }
> +
> +  return RetVal;
> +}
> +
> diff --git a/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c
> b/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c
> index a638de8..289697a 100644
> --- a/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c
> +++ b/ShellPkg/Library/UefiShellLevel3CommandsLib/Echo.c
> @@ -2,7 +2,7 @@
>    Main file for Echo shell level 3 function.
> 
>    (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
> -  Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved. 
> <BR>
> +  Copyright (c) 2009 - 2016, 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 @@ -17,12 +17,6 @@
> 
>  #include <Library/ShellLib.h>
> 
> -STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
> -  {L"-on", TypeFlag},
> -  {L"-off", TypeFlag},
> -  {NULL, TypeMax}
> -  };
> -
>  /**
>    Function for 'echo' command.
> 
> @@ -36,86 +30,85 @@ ShellCommandRunEcho (
>    IN EFI_SYSTEM_TABLE  *SystemTable
>    )
>  {
> -  EFI_STATUS          Status;
> -  LIST_ENTRY          *Package;
> -  SHELL_STATUS        ShellStatus;
> -  UINTN               ParamCount;
> -  CHAR16              *ProblemParam;
> +  CHAR16              *OriginalCmdLine;
> +  SHELL_STATUS        Status;
>    UINTN               Size;
>    CHAR16              *PrintString;
> +  CHAR16              *Walker;
> +  CHAR16              *TempParameter;
> +  BOOLEAN             OnFlag;
> +  BOOLEAN             OffFlag;
> +  UINTN               Count;
> +
> +  OriginalCmdLine = ShellGetOriginalCmdLine();  if (OriginalCmdLine 
> + == NULL) {
> +    return SHELL_OUT_OF_RESOURCES;
> +  }
> 
>    Size                = 0;
> -  ProblemParam        = NULL;
>    PrintString         = NULL;
> -  ShellStatus         = SHELL_SUCCESS;
> -
> -  //
> -  // initialize the shell lib (we must be in non-auto-init...)
> -  //
> -  Status = ShellInitialize();
> -  ASSERT_EFI_ERROR(Status);
> -
> -  //
> -  // parse the command line
> -  //
> -  Status = ShellCommandLineParseEx (ParamList, &Package, 
> &ProblemParam, TRUE, TRUE);
> -  if (EFI_ERROR(Status)) {
> -    if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
> -      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM),
> gShellLevel3HiiHandle, L"echo", ProblemParam);
> -      FreePool(ProblemParam);
> -      ShellStatus = SHELL_INVALID_PARAMETER;
> -    } else {
> -      ASSERT(FALSE);
> -    }
> -  } else {
> -    //
> -    // check for "-?"
> -    //
> -    if (ShellCommandLineGetFlag(Package, L"-?")) {
> -      ASSERT(FALSE);
> +  TempParameter       = NULL;
> +  Status              = EFI_SUCCESS;
> +  OnFlag              = FALSE;
> +  OffFlag             = FALSE;
> +
> +  Size = StrSize(OriginalCmdLine);
> +  TempParameter  = AllocateZeroPool(Size);  ASSERT (TempParameter != 
> + NULL);
> +
> +  for ( Count = 0
> +      , Walker = (CHAR16*)OriginalCmdLine
> +      ; Walker != NULL && *Walker != CHAR_NULL
> +      ; Count++
> +      ) {
> +    if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size,
> FALSE))) {
> +      break;
>      }
> -    if (ShellCommandLineGetFlag(Package, L"-on")) {
> -      //
> -      // Turn it on
> -      //
> -      ShellCommandSetEchoState(TRUE);
> -    } else if (ShellCommandLineGetFlag(Package, L"-off")) {
> -      //
> -      // turn it off
> -      //
> -      ShellCommandSetEchoState(FALSE);
> -    } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) {
> -      //
> -      // output its current state
> -      //
> -      if (ShellCommandGetEchoState()) {
> -        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ECHO_ON),
> gShellLevel3HiiHandle);
> -      } else {
> -        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_ECHO_OFF),
> gShellLevel3HiiHandle);
> +
> +    if (Count == 1) {
> +      if (gUnicodeCollation->StriColl(gUnicodeCollation, 
> + TempParameter, L"-
> on") == 0 ) {
> +        OnFlag = TRUE;
>        }
> -    } else {
> -      //
> -      // print the line
> -      //
> -      for ( ParamCount = 1
> -          ; ShellCommandLineGetRawValue(Package, ParamCount) != NULL
> -          ; ParamCount++
> -         ) {
> -        StrnCatGrow(&PrintString, &Size,
> ShellCommandLineGetRawValue(Package, ParamCount), 0);
> -        if (ShellCommandLineGetRawValue(Package, ParamCount+1) != NULL) {
> -          StrnCatGrow(&PrintString, &Size, L" ", 0);
> -        }
> +      if (gUnicodeCollation->StriColl(gUnicodeCollation, 
> + TempParameter, L"-
> off") == 0 ) {
> +        OffFlag = TRUE;
>        }
> -      ShellPrintEx(-1, -1, L"%s\r\n", PrintString);
> -      SHELL_FREE_NON_NULL(PrintString);
>      }
> +  }
> +
> +  if ((OnFlag || OffFlag) && Count != 2 ) {
> +    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN
> (STR_ECHO_INVALID_PARAM), gShellLevel3HiiHandle, L"echo", 
> L"-on/-off");
> +    Status = SHELL_INVALID_PARAMETER;
> +    goto Done;
> +  }
> 
> -    //
> -    // free the command line package
> -    //
> -    ShellCommandLineFreeVarList (Package);
> +  if (OnFlag) {
> +    ShellCommandSetEchoState(TRUE);
> +    Status = SHELL_SUCCESS;
> +    goto Done;
> +  } else if (OffFlag) {
> +    ShellCommandSetEchoState(FALSE);
> +    Status = SHELL_SUCCESS;
> +    goto Done;
>    }
> 
> -  return (ShellStatus);
> +  Walker = OriginalCmdLine + StrLen(L"echo");  if  (StrLen (Walker) 
> + <= 1) {
> +    Status = SHELL_SUCCESS;
> +    goto Done;
> +  } else {
> +    Walker++;
> +    PrintString = AllocateCopyPool(StrSize(Walker), Walker);
> +    ASSERT (PrintString != NULL);
> +    ShellPrintEx(-1, -1, L"%s\r\n", PrintString);  }
> +
> +  Status = SHELL_SUCCESS;
> +
> +Done:
> +  SHELL_FREE_NON_NULL(TempParameter);
> +  SHELL_FREE_NON_NULL(PrintString);
> +  SHELL_FREE_NON_NULL(OriginalCmdLine);
> +  return Status;
> +
>  }
> 
> diff --git
> a/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3Commands
> Lib.uni
> b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3Commands
> Lib.uni
> index fc9c5d4..f6978d2 100644
> ---
> a/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3Commands
> Lib.uni
> +++
> b/ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3Commands
> Lib.uni
> @@ -55,6 +55,7 @@
> 
>  #string STR_ECHO_ON               #language en-US "Echo is on.\r\n"
>  #string STR_ECHO_OFF              #language en-US "Echo is off.\r\n"
> +#string STR_ECHO_INVALID_PARAM    #language en-US "%H%s%N: Invalid
> - too many parameters after '%s'\r\n"
> 
>  #string STR_PAUSE_PROMPT          #language en-US "Enter 'q' to quit, any
> other key to continue:\r\n"
> 
> --
> 2.7.1.windows.2

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to