From: Tapan Shah Date: Wed, 3 Jun 2015 20:33:41 +0000 (+0000) Subject: ShellPkg: Add pipe support for parse command X-Git-Tag: edk2-stable201903~9705 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=421fbf99f82f6925c395cbd25821ccec09582b6b ShellPkg: Add pipe support for parse command parse reads data from StdIn when pipe is used and does not require –sfo output stored in a file. (e.g.: fs0:\> ls *.nsh –sfo | parse FileInfo 2) Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Tapan Shah Reviewed-by: Jaben Carsey git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17555 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c index f224925760..b6d5d991a6 100644 --- a/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c +++ b/ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.c @@ -1,7 +1,7 @@ /** @file Provides interface to shell internal functions for shell commands. - (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
+ (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -1622,7 +1622,6 @@ ShellFileHandleEof( gEfiShellProtocol->GetFilePosition(Handle, &Pos); Info = gEfiShellProtocol->GetFileInfo (Handle); - ASSERT(Info != NULL); gEfiShellProtocol->SetFilePosition(Handle, Pos); if (Info == NULL) { diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c index 69a104389f..545b7af342 100644 --- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c +++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c @@ -15,6 +15,179 @@ #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; + } +} + +/** + Function to read a single line (up to but not including the \n) using StdIn data from a SHELL_FILE_HANDLE. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + @param[in, out] Buffer The pointer to buffer to read into. + @param[in, out] Size The pointer to number of bytes in Buffer. + @param[in] Truncate If the buffer is large enough, this has no effect. + If the buffer is is too small and Truncate is TRUE, + the line will be truncated. + If the buffer is is too small and Truncate is FALSE, + then no read will occur. + + @retval EFI_SUCCESS The operation was successful. The line is stored in + Buffer. + @retval EFI_INVALID_PARAMETER Handle was NULL. + @retval EFI_INVALID_PARAMETER Size was NULL. + @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line. + Size was updated to the minimum space required. +**/ +EFI_STATUS +EFIAPI +ShellFileHandleReadStdInLine( + IN SHELL_FILE_HANDLE Handle, + IN OUT CHAR16 *Buffer, + IN OUT UINTN *Size, + IN BOOLEAN Truncate + ) +{ + EFI_STATUS Status; + CHAR16 CharBuffer; + UINTN CharSize; + UINTN CountSoFar; + UINT64 OriginalFilePosition; + + + if (Handle == NULL + ||Size == NULL + ){ + return (EFI_INVALID_PARAMETER); + } + if (Buffer == NULL) { + ASSERT(*Size == 0); + } else { + *Buffer = CHAR_NULL; + } + gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition); + + for (CountSoFar = 0;;CountSoFar++){ + CharBuffer = 0; + CharSize = sizeof(CHAR16); + Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer); + if ( EFI_ERROR(Status) + || CharSize == 0 + || (CharBuffer == L'\n') + ){ + break; + } + // + // if we have space save it... + // + if ((CountSoFar+1)*sizeof(CHAR16) < *Size){ + ASSERT(Buffer != NULL); + ((CHAR16*)Buffer)[CountSoFar] = CharBuffer; + ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL; + } + } + + // + // if we ran out of space tell when... + // + if ((CountSoFar+1)*sizeof(CHAR16) > *Size){ + *Size = (CountSoFar+1)*sizeof(CHAR16); + if (!Truncate) { + gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition); + } else { + DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine")); + } + return (EFI_BUFFER_TOO_SMALL); + } + while(Buffer[StrLen(Buffer)-1] == L'\r') { + Buffer[StrLen(Buffer)-1] = CHAR_NULL; + } + + return (Status); +} + + +/** + Function to read a single line using StdIn from a SHELL_FILE_HANDLE. The \n is not included in the returned + buffer. The returned buffer must be callee freed. + + If the position upon start is 0, then the Ascii Boolean will be set. This should be + maintained and not changed for all operations with the same file. + + @param[in] Handle SHELL_FILE_HANDLE to read from. + + @return The line of text from the file. + @retval NULL There was not enough memory available. + + @sa ShellFileHandleReadLine +**/ +CHAR16* +EFIAPI +ParseReturnStdInLine ( + IN SHELL_FILE_HANDLE Handle + ) +{ + CHAR16 *RetVal; + UINTN Size; + EFI_STATUS Status; + + Size = 0; + RetVal = NULL; + + Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE); + if (Status == EFI_BUFFER_TOO_SMALL) { + RetVal = AllocateZeroPool(Size); + if (RetVal == NULL) { + return (NULL); + } + Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE); + + } + if (EFI_ERROR(Status) && (RetVal != NULL)) { + FreePool(RetVal); + RetVal = NULL; + } + return (RetVal); +} + /** Do the actual parsing of the file. the file should be SFO output from a shell command or a similar format. @@ -24,6 +197,7 @@ @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. @@ -35,7 +209,8 @@ PerformParsing( IN CONST CHAR16 *TableName, IN CONST UINTN ColumnIndex, IN CONST UINTN TableNameInstance, - IN CONST UINTN ShellCommandInstance + IN CONST UINTN ShellCommandInstance, + IN BOOLEAN StreamingUnicode ) { SHELL_FILE_HANDLE FileHandle; @@ -62,9 +237,14 @@ PerformParsing( ShellStatus = SHELL_NOT_FOUND; } else { for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) { - TempLine = ShellFileHandleReturnLine(FileHandle, &Ascii); - if (TempLine == NULL) { - break; + if (StreamingUnicode) { + TempLine = ParseReturnStdInLine (FileHandle); + } else { + TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii); + } + + if ((TempLine == NULL) || (*TempLine == CHAR_NULL && StreamingUnicode == TRUE)) { + break; } // @@ -80,7 +260,11 @@ PerformParsing( if (LoopVariable == ShellCommandInstance) { LoopVariable = 0; while(1) { - TempLine = ShellFileHandleReturnLine(FileHandle, &Ascii); + if (StreamingUnicode) { + TempLine = ParseReturnStdInLine (FileHandle); + } else { + TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii); + } if (TempLine == NULL || *TempLine == CHAR_NULL || StrStr (TempLine, L"ShellCommand,") == TempLine) { @@ -99,7 +283,7 @@ PerformParsing( } if (ColumnLoop == ColumnIndex) { if (ColumnPointer == NULL) { - ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index"); + 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",\""); @@ -156,9 +340,11 @@ ShellCommandRunParse ( SHELL_STATUS ShellStatus; UINTN ShellCommandInstance; UINTN TableNameInstance; + BOOLEAN StreamingUnicode; - ShellStatus = SHELL_SUCCESS; - ProblemParam = NULL; + ShellStatus = SHELL_SUCCESS; + ProblemParam = NULL; + StreamingUnicode = FALSE; // // initialize the shell lib (we must be in non-auto-init...) @@ -169,7 +355,7 @@ ShellCommandRunParse ( // // parse the command line // - Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); + 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); @@ -179,17 +365,25 @@ ShellCommandRunParse ( ASSERT(FALSE); } } else { - if (ShellCommandLineGetCount(Package) < 4) { + 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 (ShellCommandLineGetCount(Package) > 4) { + } 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 { - FileName = ShellCommandLineGetRawValue(Package, 1); - TableName = ShellCommandLineGetRawValue(Package, 2); - ColumnString = ShellCommandLineGetRawValue(Package, 3); - + 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 { @@ -201,7 +395,7 @@ ShellCommandRunParse ( ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s")); } - ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance); + ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode); } }