Revert "ShellPkg: Move FindFirstCharacter/GetNextParameter to ShellCommandLib"

This reverts commit c0bcd3433f.
The above commit causes several regression of "echo" command:
1. Double quotes are not being stripped from the final text. UEFI Shell 2.2 section 3.4.5 chops out the quotes.
2. Output redirection is not working as expected. Text is being redirected, but the ‘> …’ text should not be.
3. Inconsistent special character handling.  For example, comments with # seem to be parsed out correctly, but handing of ^ is incorrect.
In summary, ‘echo “You are ^#1” > t.txt’ results in the below content in t.txt:
 “You are ^#1” > t.txt

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Jaben Carsey <jaben.carsey@intel.com>
Reviewed-by: Tapan Shah <tapandshah@hpe.com>
This commit is contained in:
Ruiyu Ni 2016-08-23 10:40:55 +08:00
parent a747bc1eec
commit 1219c85df4
6 changed files with 258 additions and 260 deletions

View File

@ -213,7 +213,7 @@ ContainsSplit(
FirstQuote = FindNextInstance (CmdLine, L"\"", TRUE); FirstQuote = FindNextInstance (CmdLine, L"\"", TRUE);
SecondQuote = NULL; SecondQuote = NULL;
TempSpot = ShellFindFirstCharacter(CmdLine, L"|", TRUE); TempSpot = FindFirstCharacter(CmdLine, L"|", L'^');
if (FirstQuote == NULL || if (FirstQuote == NULL ||
TempSpot == NULL || TempSpot == NULL ||
@ -236,7 +236,7 @@ ContainsSplit(
continue; continue;
} else { } else {
FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE); FirstQuote = FindNextInstance (SecondQuote + 1, L"\"", TRUE);
TempSpot = ShellFindFirstCharacter(TempSpot + 1, L"|", TRUE); TempSpot = FindFirstCharacter(TempSpot + 1, L"|", L'^');
continue; continue;
} }
} }
@ -716,7 +716,6 @@ FreeResources:
} }
ShellFreeEnvVarList (); ShellFreeEnvVarList ();
ShellSetRawCmdLine (NULL);
if (ShellCommandGetExit()) { if (ShellCommandGetExit()) {
return ((EFI_STATUS)ShellCommandGetExitCode()); return ((EFI_STATUS)ShellCommandGetExitCode());
@ -1993,7 +1992,7 @@ IsValidSplit(
return (EFI_OUT_OF_RESOURCES); return (EFI_OUT_OF_RESOURCES);
} }
TempWalker = (CHAR16*)Temp; TempWalker = (CHAR16*)Temp;
if (!EFI_ERROR (ShellGetNextParameter (&TempWalker, FirstParameter, StrSize(CmdLine), TRUE))) { if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CmdLine), TRUE))) {
if (GetOperationType(FirstParameter) == Unknown_Invalid) { if (GetOperationType(FirstParameter) == Unknown_Invalid) {
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);
SetLastError(SHELL_NOT_FOUND); SetLastError(SHELL_NOT_FOUND);
@ -2042,7 +2041,7 @@ VerifySplit(
// //
// recurse to verify the next item // recurse to verify the next item
// //
TempSpot = ShellFindFirstCharacter(CmdLine, L"|", TRUE) + 1; TempSpot = FindFirstCharacter(CmdLine, L"|", L'^') + 1;
if (*TempSpot == L'a' && if (*TempSpot == L'a' &&
(*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL) (*(TempSpot + 1) == L' ' || *(TempSpot + 1) == CHAR_NULL)
) { ) {
@ -2159,7 +2158,7 @@ DoHelpUpdate(
Walker = *CmdLine; Walker = *CmdLine;
while(Walker != NULL && *Walker != CHAR_NULL) { while(Walker != NULL && *Walker != CHAR_NULL) {
if (!EFI_ERROR (ShellGetNextParameter (&Walker, CurrentParameter, StrSize(*CmdLine), TRUE))) { if (!EFI_ERROR(GetNextParameter(&Walker, &CurrentParameter, StrSize(*CmdLine), TRUE))) {
if (StrStr(CurrentParameter, L"-?") == CurrentParameter) { if (StrStr(CurrentParameter, L"-?") == CurrentParameter) {
CurrentParameter[0] = L' '; CurrentParameter[0] = L' ';
CurrentParameter[1] = L' '; CurrentParameter[1] = L' ';
@ -2590,7 +2589,6 @@ RunShellCommand(
CHAR16 *FirstParameter; CHAR16 *FirstParameter;
CHAR16 *TempWalker; CHAR16 *TempWalker;
SHELL_OPERATION_TYPES Type; SHELL_OPERATION_TYPES Type;
CHAR16 *OldCmdLine;
ASSERT(CmdLine != NULL); ASSERT(CmdLine != NULL);
if (StrLen(CmdLine) == 0) { if (StrLen(CmdLine) == 0) {
@ -2598,14 +2596,11 @@ RunShellCommand(
} }
Status = EFI_SUCCESS; Status = EFI_SUCCESS;
FirstParameter = NULL;
CleanOriginal = NULL; CleanOriginal = NULL;
OldCmdLine = NULL;
CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0); CleanOriginal = StrnCatGrow(&CleanOriginal, NULL, CmdLine, 0);
if (CleanOriginal == NULL) { if (CleanOriginal == NULL) {
Status = EFI_OUT_OF_RESOURCES; return (EFI_OUT_OF_RESOURCES);
goto Done;
} }
TrimSpaces(&CleanOriginal); TrimSpaces(&CleanOriginal);
@ -2632,36 +2627,35 @@ RunShellCommand(
// Handle case that passed in command line is just 1 or more " " characters. // Handle case that passed in command line is just 1 or more " " characters.
// //
if (StrLen (CleanOriginal) == 0) { if (StrLen (CleanOriginal) == 0) {
Status = EFI_SUCCESS; SHELL_FREE_NON_NULL(CleanOriginal);
goto Done; return (EFI_SUCCESS);
} }
Status = ProcessCommandLineToFinal(&CleanOriginal); Status = ProcessCommandLineToFinal(&CleanOriginal);
if (EFI_ERROR(Status)) { if (EFI_ERROR(Status)) {
goto Done; SHELL_FREE_NON_NULL(CleanOriginal);
return (Status);
} }
OldCmdLine = ShellGetRawCmdLine ();
ShellSetRawCmdLine (CleanOriginal);
// //
// We don't do normal processing with a split command line (output from one command input to another) // We don't do normal processing with a split command line (output from one command input to another)
// //
if (ContainsSplit(CleanOriginal)) { if (ContainsSplit(CleanOriginal)) {
Status = ProcessNewSplitCommandLine(CleanOriginal); Status = ProcessNewSplitCommandLine(CleanOriginal);
goto Done; SHELL_FREE_NON_NULL(CleanOriginal);
} return (Status);
}
// //
// We need the first parameter information so we can determine the operation type // We need the first parameter information so we can determine the operation type
// //
FirstParameter = AllocateZeroPool(StrSize(CleanOriginal)); FirstParameter = AllocateZeroPool(StrSize(CleanOriginal));
if (FirstParameter == NULL) { if (FirstParameter == NULL) {
Status = EFI_OUT_OF_RESOURCES; SHELL_FREE_NON_NULL(CleanOriginal);
goto Done; return (EFI_OUT_OF_RESOURCES);
} }
TempWalker = CleanOriginal; TempWalker = CleanOriginal;
if (!EFI_ERROR (ShellGetNextParameter (&TempWalker, FirstParameter, StrSize(CleanOriginal), TRUE))) { if (!EFI_ERROR(GetNextParameter(&TempWalker, &FirstParameter, StrSize(CleanOriginal), TRUE))) {
// //
// Depending on the first parameter we change the behavior // Depending on the first parameter we change the behavior
// //
@ -2686,12 +2680,9 @@ RunShellCommand(
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter); ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);
SetLastError(SHELL_NOT_FOUND); SetLastError(SHELL_NOT_FOUND);
} }
Done: SHELL_FREE_NON_NULL(CleanOriginal);
ShellSetRawCmdLine (OldCmdLine); SHELL_FREE_NON_NULL(FirstParameter);
SHELL_FREE_NON_NULL (OldCmdLine);
SHELL_FREE_NON_NULL (CleanOriginal);
SHELL_FREE_NON_NULL (FirstParameter);
return (Status); return (Status);
} }
@ -3129,3 +3120,37 @@ RunScriptFile (
return (Status); 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));
}

View File

@ -370,6 +370,24 @@ RunScriptFile (
IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol
); );
/**
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. Cleans off leading and trailing spaces and tabs.

View File

@ -19,6 +19,162 @@
BOOLEAN AsciiRedirection = FALSE; 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. Function to populate Argc and Argv.
@ -82,7 +238,7 @@ ParseCommandLineToArgs(
; Walker != NULL && *Walker != CHAR_NULL ; Walker != NULL && *Walker != CHAR_NULL
; Count++ ; Count++
) { ) {
if (EFI_ERROR (ShellGetNextParameter (&Walker, TempParameter, Size, TRUE))) { if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, TRUE))) {
break; break;
} }
} }
@ -100,7 +256,7 @@ ParseCommandLineToArgs(
Walker = (CHAR16*)NewCommandLine; Walker = (CHAR16*)NewCommandLine;
while(Walker != NULL && *Walker != CHAR_NULL) { while(Walker != NULL && *Walker != CHAR_NULL) {
SetMem16(TempParameter, Size, CHAR_NULL); SetMem16(TempParameter, Size, CHAR_NULL);
if (EFI_ERROR (ShellGetNextParameter (&Walker, TempParameter, Size, StripQuotation))) { if (EFI_ERROR(GetNextParameter(&Walker, &TempParameter, Size, StripQuotation))) {
Status = EFI_INVALID_PARAMETER; Status = EFI_INVALID_PARAMETER;
goto Done; goto Done;
} }

View File

@ -190,5 +190,34 @@ ParseCommandLineToArgs(
IN OUT UINTN *Argc 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_ #endif //_SHELL_PARAMETERS_PROTOCOL_PROVIDER_HEADER_

View File

@ -719,49 +719,4 @@ CatSDumpHex (
IN UINTN DataSize, IN UINTN DataSize,
IN VOID *UserData 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] IgnoreEscapedCharacter TRUE to ignore escaped characters
@return The location of the first character in the String.
@return Pointer to the ending NULL character of the String.
**/
CONST CHAR16*
EFIAPI
ShellFindFirstCharacter (
IN CONST CHAR16 *String,
IN CONST CHAR16 *CharacterList,
IN CONST BOOLEAN IgnoreEscapedCharacter
);
/**
return the next parameter from a command line string;
This function moves the next parameter from Walker into NextParameter and moves
Walker up past that parameter for recursive calling. When the final parameter
is moved *Walker will be set to NULL;
@param[in, out] Walker pointer to string of command line. Adjusted to
reminaing command line on return
@param[in, out] NextParameter 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
ShellGetNextParameter(
IN OUT CHAR16 **Walker,
IN OUT CHAR16 *NextParameter,
IN CONST UINTN Length,
IN BOOLEAN StripQuotation
);
#endif //_SHELL_COMMAND_LIB_ #endif //_SHELL_COMMAND_LIB_

View File

@ -82,191 +82,6 @@ CommandInit(
return (EFI_SUCCESS); return (EFI_SUCCESS);
} }
/**
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] IgnoreEscapedCharacter TRUE to ignore escaped characters
@return The location of the first character in the String.
@return Pointer to the ending NULL character of the String.
**/
CONST CHAR16*
EFIAPI
ShellFindFirstCharacter (
IN CONST CHAR16 *String,
IN CONST CHAR16 *CharacterList,
IN CONST BOOLEAN IgnoreEscapedCharacter
)
{
UINTN WalkChar;
UINTN WalkStr;
for (WalkStr = 0; WalkStr < StrLen (String); WalkStr++) {
if (IgnoreEscapedCharacter && (String[WalkStr] == L'^')) {
WalkStr++;
continue;
}
for (WalkChar = 0; WalkChar < StrLen (CharacterList); WalkChar++) {
if (String[WalkStr] == CharacterList[WalkChar]) {
return &String[WalkStr];
}
}
}
return &String[WalkStr];
}
/**
Return the next parameter's end from a command line string.
@param[in] String the string to parse
**/
CONST CHAR16*
FindEndOfParameter(
IN CONST CHAR16 *String
)
{
CONST CHAR16 *First;
CONST CHAR16 *CloseQuote;
First = ShellFindFirstCharacter (String, L" \"", TRUE);
//
// 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 = ShellFindFirstCharacter (First+1, L"\"", TRUE);
//
// 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 NextParameter and moves
Walker up past that parameter for recursive calling. When the final parameter
is moved *Walker will be set to NULL;
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] NextParameter 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
ShellGetNextParameter (
IN OUT CHAR16 **Walker,
IN OUT CHAR16 *NextParameter,
IN CONST UINTN Length,
IN BOOLEAN StripQuotation
)
{
CONST CHAR16 *NextDelim;
if (Walker == NULL
||*Walker == NULL
||NextParameter == 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 (
*Walker = NULL;
);
return (EFI_INVALID_PARAMETER);
}
NextDelim = FindEndOfParameter(*Walker);
if (NextDelim == NULL){
DEBUG_CODE (
*Walker = NULL;
);
return (EFI_NOT_FOUND);
}
StrnCpyS(NextParameter, Length / sizeof(CHAR16), (*Walker), NextDelim - *Walker);
//
// Add a CHAR_NULL if we didnt get one via the copy
//
if (*NextDelim != CHAR_NULL) {
NextParameter[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 = ShellFindFirstCharacter(NextParameter, L"\"^", FALSE)
; *NextDelim != CHAR_NULL
; NextDelim = ShellFindFirstCharacter(NextDelim, L"\"^", FALSE)
) {
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. Constructor for the Shell Command library.