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 <tapandshah@hp.com>
Reviewed-by: Jaben Carsey <jaben.carsey@intel.com>



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 f224925..b6d5d99 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.<BR>

+  (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>

   Copyright (c) 2009 - 2014, 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

@@ -1622,7 +1622,6 @@
 

   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 69a1043..545b7af 100644
--- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c
+++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c
@@ -16,6 +16,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 @@
   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 @@
     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 @@
     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 @@
             }

             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 @@
   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 @@
   //

   // 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 @@
       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 @@
         ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s"));

       }

 

-      ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance);

+      ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode);

     }

   }