Home | History | Annotate | Download | only in UefiShellLevel2CommandsLib
      1 /** @file
      2   Main file for Parse shell level 2 function.
      3 
      4   (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "UefiShellLevel2CommandsLib.h"
     17 
     18 /**
     19   Check if data is coming from StdIn output.
     20 
     21   @param[in] None
     22 
     23   @retval TRUE  StdIn stream data available to parse
     24   @retval FALSE StdIn stream data is not available to parse.
     25 **/
     26 BOOLEAN
     27 IsStdInDataAvailable (
     28   VOID
     29   )
     30 {
     31   SHELL_FILE_HANDLE FileHandle;
     32   EFI_STATUS        Status;
     33   CHAR16            CharBuffer;
     34   UINTN             CharSize;
     35   UINT64            OriginalFilePosition;
     36 
     37   Status               = EFI_SUCCESS;
     38   FileHandle           = NULL;
     39   OriginalFilePosition = 0;
     40 
     41   if (ShellOpenFileByName (L">i", &FileHandle, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) {
     42     CharSize = sizeof(CHAR16);
     43     gEfiShellProtocol->GetFilePosition (FileHandle, &OriginalFilePosition);
     44     Status = gEfiShellProtocol->ReadFile (FileHandle, &CharSize, &CharBuffer);
     45     if (EFI_ERROR (Status) || (CharSize != sizeof(CHAR16))) {
     46       return FALSE;
     47     }
     48     gEfiShellProtocol->SetFilePosition(FileHandle, OriginalFilePosition);
     49   }
     50 
     51   if (FileHandle == NULL) {
     52     return FALSE;
     53   } else {
     54     return TRUE;
     55   }
     56 }
     57 
     58 /**
     59   Function to read a single line (up to but not including the \n) using StdIn data from a SHELL_FILE_HANDLE.
     60 
     61   If the position upon start is 0, then the Ascii Boolean will be set.  This should be
     62   maintained and not changed for all operations with the same file.
     63 
     64   @param[in]       Handle        SHELL_FILE_HANDLE to read from.
     65   @param[in, out]  Buffer        The pointer to buffer to read into.
     66   @param[in, out]  Size          The pointer to number of bytes in Buffer.
     67   @param[in]       Truncate      If the buffer is large enough, this has no effect.
     68                                  If the buffer is is too small and Truncate is TRUE,
     69                                  the line will be truncated.
     70                                  If the buffer is is too small and Truncate is FALSE,
     71                                  then no read will occur.
     72 
     73   @retval EFI_SUCCESS           The operation was successful.  The line is stored in
     74                                 Buffer.
     75   @retval EFI_INVALID_PARAMETER Handle was NULL.
     76   @retval EFI_INVALID_PARAMETER Size was NULL.
     77   @retval EFI_BUFFER_TOO_SMALL  Size was not large enough to store the line.
     78                                 Size was updated to the minimum space required.
     79 **/
     80 EFI_STATUS
     81 ShellFileHandleReadStdInLine(
     82   IN SHELL_FILE_HANDLE          Handle,
     83   IN OUT CHAR16                 *Buffer,
     84   IN OUT UINTN                  *Size,
     85   IN BOOLEAN                    Truncate
     86   )
     87 {
     88   EFI_STATUS  Status;
     89   CHAR16      CharBuffer;
     90   UINTN       CharSize;
     91   UINTN       CountSoFar;
     92   UINT64      OriginalFilePosition;
     93 
     94 
     95   if (Handle == NULL
     96     ||Size   == NULL
     97    ){
     98     return (EFI_INVALID_PARAMETER);
     99   }
    100   if (Buffer == NULL) {
    101     ASSERT(*Size == 0);
    102   } else {
    103     *Buffer = CHAR_NULL;
    104   }
    105   gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition);
    106 
    107   for (CountSoFar = 0;;CountSoFar++){
    108     CharBuffer = 0;
    109     CharSize = sizeof(CHAR16);
    110     Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
    111     if (  EFI_ERROR(Status)
    112        || CharSize == 0
    113        || (CharBuffer == L'\n')
    114      ){
    115       break;
    116     }
    117     //
    118     // if we have space save it...
    119     //
    120     if ((CountSoFar+1)*sizeof(CHAR16) < *Size){
    121       ASSERT(Buffer != NULL);
    122       ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;
    123       ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;
    124     }
    125   }
    126 
    127   //
    128   // if we ran out of space tell when...
    129   //
    130   if ((CountSoFar+1)*sizeof(CHAR16) > *Size){
    131     *Size = (CountSoFar+1)*sizeof(CHAR16);
    132     if (!Truncate) {
    133       gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
    134     } else {
    135       DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
    136     }
    137     return (EFI_BUFFER_TOO_SMALL);
    138   }
    139   while(Buffer[StrLen(Buffer)-1] == L'\r') {
    140     Buffer[StrLen(Buffer)-1] = CHAR_NULL;
    141   }
    142 
    143   return (Status);
    144 }
    145 
    146 
    147 /**
    148   Function to read a single line using StdIn from a SHELL_FILE_HANDLE. The \n is not included in the returned
    149   buffer.  The returned buffer must be callee freed.
    150 
    151   If the position upon start is 0, then the Ascii Boolean will be set.  This should be
    152   maintained and not changed for all operations with the same file.
    153 
    154   @param[in]       Handle        SHELL_FILE_HANDLE to read from.
    155 
    156   @return                        The line of text from the file.
    157   @retval NULL                   There was not enough memory available.
    158 
    159   @sa ShellFileHandleReadLine
    160 **/
    161 CHAR16*
    162 ParseReturnStdInLine (
    163   IN SHELL_FILE_HANDLE Handle
    164   )
    165 {
    166   CHAR16          *RetVal;
    167   UINTN           Size;
    168   EFI_STATUS      Status;
    169 
    170   Size   = 0;
    171   RetVal = NULL;
    172 
    173   Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE);
    174   if (Status == EFI_BUFFER_TOO_SMALL) {
    175     RetVal = AllocateZeroPool(Size);
    176     if (RetVal == NULL) {
    177       return (NULL);
    178     }
    179     Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE);
    180 
    181   }
    182   if (EFI_ERROR(Status) && (RetVal != NULL)) {
    183     FreePool(RetVal);
    184     RetVal = NULL;
    185   }
    186   return (RetVal);
    187 }
    188 
    189 /**
    190   Handle stings for SFO Output with escape character ^ in a string
    191   1. Quotation marks in the string must be escaped by using a ^ character (i.e. ^").
    192   2. The ^ character may be inserted using ^^.
    193 
    194   @param[in]  String  The Unicode NULL-terminated string.
    195 
    196   @retval NewString   The new string handled for SFO.
    197 **/
    198 EFI_STRING
    199 HandleStringWithEscapeCharForParse (
    200   IN      CHAR16  *String
    201   )
    202 {
    203   EFI_STRING  NewStr;
    204   EFI_STRING  StrWalker;
    205   EFI_STRING  ReturnStr;
    206 
    207   if (String == NULL) {
    208     return NULL;
    209   }
    210 
    211   //
    212   // start to parse the input string.
    213   //
    214   NewStr = AllocateZeroPool (StrSize (String));
    215   if (NewStr == NULL) {
    216     return NULL;
    217   }
    218   ReturnStr = NewStr;
    219   StrWalker = String;
    220   while (*StrWalker != CHAR_NULL) {
    221     if (*StrWalker == L'^' && (*(StrWalker + 1) == L'^' || *(StrWalker + 1) == L'"')) {
    222       *NewStr = *(StrWalker + 1);
    223       StrWalker++;
    224     } else {
    225       *NewStr = *StrWalker;
    226     }
    227     StrWalker++;
    228     NewStr++;
    229   }
    230 
    231   return ReturnStr;
    232 }
    233 
    234 
    235 /**
    236   Do the actual parsing of the file.  the file should be SFO output from a
    237   shell command or a similar format.
    238 
    239   @param[in] FileName               The filename to open.
    240   @param[in] TableName              The name of the table to find.
    241   @param[in] ColumnIndex            The column number to get.
    242   @param[in] TableNameInstance      Which instance of the table to get (row).
    243   @param[in] ShellCommandInstance   Which instance of the command to get.
    244   @param[in] StreamingUnicode       Indicates Input file is StdIn Unicode streaming data or not
    245 
    246   @retval SHELL_NOT_FOUND     The requested instance was not found.
    247   @retval SHELL_SUCCESS       The operation was successful.
    248 **/
    249 SHELL_STATUS
    250 PerformParsing(
    251   IN CONST CHAR16 *FileName,
    252   IN CONST CHAR16 *TableName,
    253   IN CONST UINTN  ColumnIndex,
    254   IN CONST UINTN  TableNameInstance,
    255   IN CONST UINTN  ShellCommandInstance,
    256   IN BOOLEAN      StreamingUnicode
    257   )
    258 {
    259   SHELL_FILE_HANDLE FileHandle;
    260   EFI_STATUS        Status;
    261   BOOLEAN           Ascii;
    262   UINTN             LoopVariable;
    263   UINTN             ColumnLoop;
    264   CHAR16            *TempLine;
    265   CHAR16            *ColumnPointer;
    266   SHELL_STATUS      ShellStatus;
    267   CHAR16            *TempSpot;
    268   CHAR16            *SfoString;
    269 
    270   ASSERT(FileName   != NULL);
    271   ASSERT(TableName  != NULL);
    272 
    273   ShellStatus       = SHELL_SUCCESS;
    274 
    275   Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
    276   if (EFI_ERROR(Status)) {
    277     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"parse", FileName);
    278     ShellStatus = SHELL_NOT_FOUND;
    279   } else if (!EFI_ERROR (FileHandleIsDirectory (FileHandle))) {
    280     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_FILE), gShellLevel2HiiHandle, L"parse", FileName);
    281     ShellStatus = SHELL_NOT_FOUND;
    282   } else {
    283     for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) {
    284      if (StreamingUnicode) {
    285        TempLine = ParseReturnStdInLine (FileHandle);
    286      } else {
    287        TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
    288      }
    289 
    290       if ((TempLine == NULL) || (*TempLine == CHAR_NULL && StreamingUnicode)) {
    291          break;
    292       }
    293 
    294       //
    295       // Search for "ShellCommand," in the file to start the SFO table
    296       // for a given ShellCommand.  The UEFI Shell spec does not specify
    297       // a space after the comma.
    298       //
    299       if (StrStr (TempLine, L"ShellCommand,") == TempLine) {
    300         LoopVariable++;
    301       }
    302       SHELL_FREE_NON_NULL(TempLine);
    303     }
    304     if (LoopVariable == ShellCommandInstance) {
    305       LoopVariable = 0;
    306       while(1) {
    307         if (StreamingUnicode) {
    308           TempLine = ParseReturnStdInLine (FileHandle);
    309         } else {
    310           TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
    311         }
    312         if (TempLine == NULL
    313             || *TempLine == CHAR_NULL
    314             || StrStr (TempLine, L"ShellCommand,") == TempLine) {
    315           SHELL_FREE_NON_NULL(TempLine);
    316           break;
    317         }
    318         if (StrStr (TempLine, TableName) == TempLine) {
    319           LoopVariable++;
    320           if (LoopVariable == TableNameInstance
    321               || (TableNameInstance == (UINTN)-1)) {
    322             for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) {
    323               ColumnPointer = StrStr (ColumnPointer, L",\"");
    324               if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL){
    325                 ColumnPointer++;
    326               }
    327             }
    328             if (ColumnLoop == ColumnIndex) {
    329               if (ColumnPointer == NULL) {
    330                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index");
    331                 ShellStatus = SHELL_INVALID_PARAMETER;
    332               } else {
    333                 TempSpot = StrStr (ColumnPointer, L",\"");
    334                 if (TempSpot != NULL) {
    335                   *TempSpot = CHAR_NULL;
    336                 }
    337                 while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' '){
    338                   ColumnPointer++;
    339                 }
    340                 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L'\"'){
    341                   ColumnPointer++;
    342                 }
    343                 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[StrLen (ColumnPointer) - 1] == L'\"'){
    344                   ColumnPointer[StrLen (ColumnPointer) - 1] = CHAR_NULL;
    345                 }
    346                 SfoString = HandleStringWithEscapeCharForParse (ColumnPointer);
    347                 if (SfoString != NULL) {
    348                   ShellPrintEx (-1, -1, L"%s\r\n", SfoString);
    349                   SHELL_FREE_NON_NULL (SfoString);
    350                 }
    351               }
    352             }
    353           }
    354         }
    355         SHELL_FREE_NON_NULL(TempLine);
    356       }
    357     }
    358   }
    359   return (ShellStatus);
    360 }
    361 
    362 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
    363   {L"-i", TypeValue},
    364   {L"-s", TypeValue},
    365   {NULL, TypeMax}
    366   };
    367 
    368 /**
    369   Function for 'parse' command.
    370 
    371   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    372   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    373 **/
    374 SHELL_STATUS
    375 EFIAPI
    376 ShellCommandRunParse (
    377   IN EFI_HANDLE        ImageHandle,
    378   IN EFI_SYSTEM_TABLE  *SystemTable
    379   )
    380 {
    381   EFI_STATUS          Status;
    382   LIST_ENTRY          *Package;
    383   CHAR16              *ProblemParam;
    384   CONST CHAR16        *FileName;
    385   CONST CHAR16        *TableName;
    386   CONST CHAR16        *ColumnString;
    387   SHELL_STATUS        ShellStatus;
    388   UINTN               ShellCommandInstance;
    389   UINTN               TableNameInstance;
    390   BOOLEAN             StreamingUnicode;
    391 
    392   ShellStatus      = SHELL_SUCCESS;
    393   ProblemParam     = NULL;
    394   StreamingUnicode = FALSE;
    395 
    396   //
    397   // initialize the shell lib (we must be in non-auto-init...)
    398   //
    399   Status = ShellInitialize();
    400   ASSERT_EFI_ERROR(Status);
    401 
    402   //
    403   // parse the command line
    404   //
    405   Status = ShellCommandLineParseEx (ParamList, &Package, &ProblemParam, TRUE, FALSE);
    406   if (EFI_ERROR(Status)) {
    407     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
    408       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"parse", ProblemParam);
    409       FreePool(ProblemParam);
    410       ShellStatus = SHELL_INVALID_PARAMETER;
    411     } else {
    412       ASSERT(FALSE);
    413     }
    414   } else {
    415     StreamingUnicode = IsStdInDataAvailable ();
    416     if ((!StreamingUnicode && (ShellCommandLineGetCount(Package) < 4)) ||
    417         (ShellCommandLineGetCount(Package) < 3)) {
    418       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"parse");
    419       ShellStatus = SHELL_INVALID_PARAMETER;
    420     } else if ((StreamingUnicode && (ShellCommandLineGetCount(Package) > 3)) ||
    421                 (ShellCommandLineGetCount(Package) > 4)) {
    422       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"parse");
    423       ShellStatus = SHELL_INVALID_PARAMETER;
    424     } else {
    425       if (StreamingUnicode) {
    426         FileName         = L">i";
    427         TableName        = ShellCommandLineGetRawValue(Package, 1);
    428         ColumnString     = ShellCommandLineGetRawValue(Package, 2);
    429       } else {
    430         FileName         = ShellCommandLineGetRawValue(Package, 1);
    431         TableName        = ShellCommandLineGetRawValue(Package, 2);
    432         ColumnString     = ShellCommandLineGetRawValue(Package, 3);
    433       }
    434       if (ShellCommandLineGetValue(Package, L"-i") == NULL) {
    435         TableNameInstance = (UINTN)-1;
    436       } else {
    437         TableNameInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-i"));
    438       }
    439       if (ShellCommandLineGetValue(Package, L"-s") == NULL) {
    440         ShellCommandInstance = 1;
    441       } else {
    442         ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s"));
    443       }
    444 
    445       ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode);
    446     }
    447   }
    448 
    449   //
    450   // free the command line package
    451   //
    452   ShellCommandLineFreeVarList (Package);
    453 
    454   return (ShellStatus);
    455 }
    456 
    457