mirror of https://github.com/acidanthera/audk.git
ShellPkg: refine command line parsing
Correctly divide up parameters for Argc/Argv including quote ("), escape (^), and space ( ) processing. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jaben Carsey <Jaben.carsey@intel.com> Reviewed-by: Joe Peterson <joe.peterson@intel.com> Reviewed-by: Tapan Shah <tapandshah@hp.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16673 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
fdd52bde51
commit
14030c5c85
|
@ -1870,12 +1870,12 @@ IsValidSplit(
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2030,24 +2030,25 @@ DoHelpUpdate(
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2499,27 +2500,30 @@ RunCommand(
|
|||
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);
|
||||
|
|
|
@ -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,7 +18,79 @@
|
|||
#include "Shell.h"
|
||||
|
||||
/**
|
||||
return the next parameter from a command line string;
|
||||
Return the next location of a non-escaped character from a command line string;
|
||||
|
||||
@param[in] String the string to parse
|
||||
@param[in] Character the character to look for
|
||||
|
||||
@retval the location of the character in the string or the end of the string
|
||||
**/
|
||||
CONST CHAR16*
|
||||
EFIAPI
|
||||
FindCharacter(
|
||||
IN CONST CHAR16 *String,
|
||||
IN CONST CHAR16 Character
|
||||
)
|
||||
{
|
||||
CONST CHAR16 *Walker;
|
||||
|
||||
for (Walker = String ; *Walker != Character && *Walker != CHAR_NULL; Walker++) {
|
||||
if (*Walker == L'^') {
|
||||
Walker++;
|
||||
}
|
||||
}
|
||||
return Walker;
|
||||
}
|
||||
|
||||
/**
|
||||
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 *NextSpace;
|
||||
CONST CHAR16 *NextQuote;
|
||||
CONST CHAR16 *First;
|
||||
CONST CHAR16 *CloseQuote;
|
||||
|
||||
NextSpace = FindCharacter (String, L' ' );
|
||||
NextQuote = FindCharacter (String, L'\"');
|
||||
First = MIN (NextQuote, NextSpace);
|
||||
|
||||
//
|
||||
// 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 == NextSpace) {
|
||||
return (NextSpace);
|
||||
}
|
||||
|
||||
CloseQuote = FindCharacter (First+1, L'\"');
|
||||
|
||||
//
|
||||
// We did not find a terminator... return the end of the string
|
||||
//
|
||||
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
|
||||
|
@ -27,12 +99,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,
|
||||
|
@ -41,12 +118,15 @@ GetNextParameter(
|
|||
)
|
||||
{
|
||||
CHAR16 *NextDelim;
|
||||
CHAR16 *TempLoc;
|
||||
|
||||
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 +139,80 @@ GetNextParameter(
|
|||
// 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 = (CHAR16*)FindEndOfParameter(*Walker);
|
||||
|
||||
if (NextDelim == NULL){
|
||||
DEBUG_CODE_BEGIN();
|
||||
*Walker = NULL;
|
||||
DEBUG_CODE_END();
|
||||
return (EFI_NOT_FOUND);
|
||||
}
|
||||
|
||||
StrnCpy(*TempParameter, (*Walker), NextDelim - *Walker);
|
||||
|
||||
//
|
||||
// Add a CHAR_NULL if we didnt get one via the copy
|
||||
//
|
||||
if (*NextDelim != CHAR_NULL) {
|
||||
(*TempParameter)[NextDelim - *Walker] = CHAR_NULL;
|
||||
}
|
||||
|
||||
*Walker = NextDelim;
|
||||
|
||||
//
|
||||
// Now remove any quotes surrounding entire parameters
|
||||
//
|
||||
if ((*TempParameter)[0] == L'\"' && (*TempParameter)[StrLen (*TempParameter)-1] == L'\"') {
|
||||
(*TempParameter)[StrLen (*TempParameter)-1] = CHAR_NULL;
|
||||
CopyMem ((*TempParameter), (*TempParameter)+1, StrSize ((*TempParameter)+1));
|
||||
}
|
||||
|
||||
//
|
||||
// we have a quoted parameter
|
||||
// could be the last parameter, but SHOULD have a trailing quote
|
||||
// Remove any non-escaped quotes in the string
|
||||
//
|
||||
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 - ((*Walker)+1) == 0) {
|
||||
//
|
||||
// found ""
|
||||
//
|
||||
*(*TempParameter) = CHAR_NULL;
|
||||
*Walker = NextDelim + 1;
|
||||
} else if (NextDelim != NULL) {
|
||||
|
||||
//
|
||||
// Copy ensuring that both quotes are left in place.
|
||||
//
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
for (NextDelim = StrStr(*TempParameter, L"\""); NextDelim != NULL && *NextDelim != CHAR_NULL; NextDelim = StrStr(NextDelim, L"\"")) {
|
||||
//
|
||||
// we have a regular parameter (no quote) OR
|
||||
// we have the final parameter (no trailing space)
|
||||
// Make sure I found a quote character properly.
|
||||
//
|
||||
NextDelim = StrStr((*Walker), L" ");
|
||||
if (NextDelim != NULL) {
|
||||
StrnCpy(*TempParameter, *Walker, NextDelim - (*Walker));
|
||||
(*TempParameter)[NextDelim - (*Walker)] = CHAR_NULL;
|
||||
*Walker = NextDelim+1;
|
||||
ASSERT(*NextDelim == L'\"');
|
||||
|
||||
//
|
||||
// Only remove quotes that do not have a preceeding ^
|
||||
//
|
||||
if ((NextDelim > (*TempParameter) && (*(NextDelim - 1) != L'^')) || (NextDelim == (*TempParameter))) {
|
||||
CopyMem (NextDelim, NextDelim + 1, StrSize (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]));
|
||||
NextDelim++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
//
|
||||
// Remove any escape charactersin the parameter before returning it
|
||||
// all escape character processing is complete at this time
|
||||
//
|
||||
for (NextDelim = StrStr(*TempParameter, L"^"); NextDelim != NULL && *NextDelim != CHAR_NULL; NextDelim = StrStr(NextDelim, L"^")) {
|
||||
//
|
||||
// Make sure I found an escape character properly.
|
||||
//
|
||||
ASSERT(*NextDelim == L'^');
|
||||
|
||||
CopyMem (NextDelim, NextDelim + 1, StrSize (NextDelim + 1));
|
||||
|
||||
//
|
||||
// If we had 2 escapes in a row, leave one behind
|
||||
//
|
||||
if (*NextDelim == L'^') {
|
||||
NextDelim++;
|
||||
}
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -143,6 +222,9 @@ GetNextParameter(
|
|||
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 +264,12 @@ ParseCommandLineToArgs(
|
|||
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 +284,11 @@ ParseCommandLineToArgs(
|
|||
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);
|
||||
|
|
|
@ -192,8 +192,10 @@ ParseCommandLineToArgs(
|
|||
@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,
|
||||
|
|
Loading…
Reference in New Issue