/** @file
Main file for Parse shell level 2 function.
(C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiShellLevel2CommandsLib.h"
/**
Check if data is coming from StdIn output.
@param[in] None
@retval TRUE StdIn stream data available to parse
@retval FALSE StdIn stream data is not available to parse.
**/
BOOLEAN
IsStdInDataAvailable (
VOID
)
{
SHELL_FILE_HANDLE FileHandle;
EFI_STATUS Status;
CHAR16 CharBuffer;
UINTN CharSize;
UINT64 OriginalFilePosition;
Status = EFI_SUCCESS;
FileHandle = NULL;
OriginalFilePosition = 0;
if (ShellOpenFileByName (L">i", &FileHandle, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) {
CharSize = sizeof (CHAR16);
gEfiShellProtocol->GetFilePosition (FileHandle, &OriginalFilePosition);
Status = gEfiShellProtocol->ReadFile (FileHandle, &CharSize, &CharBuffer);
if (EFI_ERROR (Status) || (CharSize != sizeof (CHAR16))) {
return FALSE;
}
gEfiShellProtocol->SetFilePosition (FileHandle, OriginalFilePosition);
}
if (FileHandle == NULL) {
return FALSE;
} else {
return TRUE;
}
}
/**
Handle stings for SFO Output with escape character ^ in a string
1. Quotation marks in the string must be escaped by using a ^ character (i.e. ^").
2. The ^ character may be inserted using ^^.
@param[in] String The Unicode NULL-terminated string.
@retval NewString The new string handled for SFO.
**/
EFI_STRING
HandleStringWithEscapeCharForParse (
IN CHAR16 *String
)
{
EFI_STRING NewStr;
EFI_STRING StrWalker;
EFI_STRING ReturnStr;
if (String == NULL) {
return NULL;
}
//
// start to parse the input string.
//
NewStr = AllocateZeroPool (StrSize (String));
if (NewStr == NULL) {
return NULL;
}
ReturnStr = NewStr;
StrWalker = String;
while (*StrWalker != CHAR_NULL) {
if ((*StrWalker == L'^') && ((*(StrWalker + 1) == L'^') || (*(StrWalker + 1) == L'"'))) {
*NewStr = *(StrWalker + 1);
StrWalker++;
} else {
*NewStr = *StrWalker;
}
StrWalker++;
NewStr++;
}
return ReturnStr;
}
/**
Do the actual parsing of the file. the file should be SFO output from a
shell command or a similar format.
@param[in] FileName The filename to open.
@param[in] TableName The name of the table to find.
@param[in] ColumnIndex The column number to get.
@param[in] TableNameInstance Which instance of the table to get (row).
@param[in] ShellCommandInstance Which instance of the command to get.
@param[in] StreamingUnicode Indicates Input file is StdIn Unicode streaming data or not
@retval SHELL_NOT_FOUND The requested instance was not found.
@retval SHELL_SUCCESS The operation was successful.
**/
SHELL_STATUS
PerformParsing (
IN CONST CHAR16 *FileName,
IN CONST CHAR16 *TableName,
IN CONST UINTN ColumnIndex,
IN CONST UINTN TableNameInstance,
IN CONST UINTN ShellCommandInstance,
IN BOOLEAN StreamingUnicode
)
{
SHELL_FILE_HANDLE FileHandle;
EFI_STATUS Status;
BOOLEAN Ascii;
UINTN LoopVariable;
UINTN ColumnLoop;
CHAR16 *TempLine;
CHAR16 *ColumnPointer;
SHELL_STATUS ShellStatus;
CHAR16 *TempSpot;
CHAR16 *SfoString;
ASSERT (FileName != NULL);
ASSERT (TableName != NULL);
ShellStatus = SHELL_SUCCESS;
Status = ShellOpenFileByName (FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"parse", FileName);
ShellStatus = SHELL_NOT_FOUND;
} else if (!EFI_ERROR (FileHandleIsDirectory (FileHandle))) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_FILE), gShellLevel2HiiHandle, L"parse", FileName);
ShellStatus = SHELL_NOT_FOUND;
} else {
for (LoopVariable = 0; LoopVariable < ShellCommandInstance && !ShellFileHandleEof (FileHandle);) {
TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
if ((TempLine == NULL) || ((*TempLine == CHAR_NULL) && StreamingUnicode)) {
break;
}
//
// Search for "ShellCommand," in the file to start the SFO table
// for a given ShellCommand. The UEFI Shell spec does not specify
// a space after the comma.
//
if (StrStr (TempLine, L"ShellCommand,") == TempLine) {
LoopVariable++;
}
SHELL_FREE_NON_NULL (TempLine);
}
if (LoopVariable == ShellCommandInstance) {
LoopVariable = 0;
while (1) {
TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
if ( (TempLine == NULL)
|| (*TempLine == CHAR_NULL)
|| (StrStr (TempLine, L"ShellCommand,") == TempLine))
{
SHELL_FREE_NON_NULL (TempLine);
break;
}
if (StrStr (TempLine, TableName) == TempLine) {
LoopVariable++;
if ( (LoopVariable == TableNameInstance)
|| (TableNameInstance == (UINTN)-1))
{
for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) {
ColumnPointer = StrStr (ColumnPointer, L",\"");
if ((ColumnPointer != NULL) && (*ColumnPointer != CHAR_NULL)) {
ColumnPointer++;
}
}
if (ColumnLoop == ColumnIndex) {
if (ColumnPointer == NULL) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index");
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
TempSpot = StrStr (ColumnPointer, L",\"");
if (TempSpot != NULL) {
*TempSpot = CHAR_NULL;
}
while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' ') {
ColumnPointer++;
}
if ((ColumnPointer != NULL) && (*ColumnPointer != CHAR_NULL) && (ColumnPointer[0] == L'\"')) {
ColumnPointer++;
}
if ((ColumnPointer != NULL) && (*ColumnPointer != CHAR_NULL) && (ColumnPointer[StrLen (ColumnPointer) - 1] == L'\"')) {
ColumnPointer[StrLen (ColumnPointer) - 1] = CHAR_NULL;
}
SfoString = HandleStringWithEscapeCharForParse (ColumnPointer);
if (SfoString != NULL) {
ShellPrintEx (-1, -1, L"%s\r\n", SfoString);
SHELL_FREE_NON_NULL (SfoString);
}
}
}
}
}
SHELL_FREE_NON_NULL (TempLine);
}
}
}
return (ShellStatus);
}
STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
{ L"-i", TypeValue },
{ L"-s", TypeValue },
{ NULL, TypeMax }
};
/**
Function for 'parse' command.
@param[in] ImageHandle Handle to the Image (NULL if Internal).
@param[in] SystemTable Pointer to the System Table (NULL if Internal).
**/
SHELL_STATUS
EFIAPI
ShellCommandRunParse (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
LIST_ENTRY *Package;
CHAR16 *ProblemParam;
CONST CHAR16 *FileName;
CONST CHAR16 *TableName;
CONST CHAR16 *ColumnString;
SHELL_STATUS ShellStatus;
UINTN ShellCommandInstance;
UINTN TableNameInstance;
BOOLEAN StreamingUnicode;
ShellStatus = SHELL_SUCCESS;
ProblemParam = NULL;
StreamingUnicode = FALSE;
//
// 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, FALSE);
if (EFI_ERROR (Status)) {
if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"parse", ProblemParam);
FreePool (ProblemParam);
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
ASSERT (FALSE);
}
} else {
StreamingUnicode = IsStdInDataAvailable ();
if ((!StreamingUnicode && (ShellCommandLineGetCount (Package) < 4)) ||
(ShellCommandLineGetCount (Package) < 3))
{
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"parse");
ShellStatus = SHELL_INVALID_PARAMETER;
} else if ((StreamingUnicode && (ShellCommandLineGetCount (Package) > 3)) ||
(ShellCommandLineGetCount (Package) > 4))
{
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"parse");
ShellStatus = SHELL_INVALID_PARAMETER;
} else {
if (StreamingUnicode) {
FileName = L">i";
TableName = ShellCommandLineGetRawValue (Package, 1);
ColumnString = ShellCommandLineGetRawValue (Package, 2);
} else {
FileName = ShellCommandLineGetRawValue (Package, 1);
TableName = ShellCommandLineGetRawValue (Package, 2);
ColumnString = ShellCommandLineGetRawValue (Package, 3);
}
if (ShellCommandLineGetValue (Package, L"-i") == NULL) {
TableNameInstance = (UINTN)-1;
} else {
TableNameInstance = ShellStrToUintn (ShellCommandLineGetValue (Package, L"-i"));
}
if (ShellCommandLineGetValue (Package, L"-s") == NULL) {
ShellCommandInstance = 1;
} else {
ShellCommandInstance = ShellStrToUintn (ShellCommandLineGetValue (Package, L"-s"));
}
ShellStatus = PerformParsing (FileName, TableName, ShellStrToUintn (ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode);
}
}
//
// free the command line package
//
ShellCommandLineFreeVarList (Package);
return (ShellStatus);
}