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 EFIAPI
     82 ShellFileHandleReadStdInLine(
     83   IN SHELL_FILE_HANDLE          Handle,
     84   IN OUT CHAR16                 *Buffer,
     85   IN OUT UINTN                  *Size,
     86   IN BOOLEAN                    Truncate
     87   )
     88 {
     89   EFI_STATUS  Status;
     90   CHAR16      CharBuffer;
     91   UINTN       CharSize;
     92   UINTN       CountSoFar;
     93   UINT64      OriginalFilePosition;
     94 
     95 
     96   if (Handle == NULL
     97     ||Size   == NULL
     98    ){
     99     return (EFI_INVALID_PARAMETER);
    100   }
    101   if (Buffer == NULL) {
    102     ASSERT(*Size == 0);
    103   } else {
    104     *Buffer = CHAR_NULL;
    105   }
    106   gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition);
    107 
    108   for (CountSoFar = 0;;CountSoFar++){
    109     CharBuffer = 0;
    110     CharSize = sizeof(CHAR16);
    111     Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);
    112     if (  EFI_ERROR(Status)
    113        || CharSize == 0
    114        || (CharBuffer == L'\n')
    115      ){
    116       break;
    117     }
    118     //
    119     // if we have space save it...
    120     //
    121     if ((CountSoFar+1)*sizeof(CHAR16) < *Size){
    122       ASSERT(Buffer != NULL);
    123       ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;
    124       ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;
    125     }
    126   }
    127 
    128   //
    129   // if we ran out of space tell when...
    130   //
    131   if ((CountSoFar+1)*sizeof(CHAR16) > *Size){
    132     *Size = (CountSoFar+1)*sizeof(CHAR16);
    133     if (!Truncate) {
    134       gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);
    135     } else {
    136       DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));
    137     }
    138     return (EFI_BUFFER_TOO_SMALL);
    139   }
    140   while(Buffer[StrLen(Buffer)-1] == L'\r') {
    141     Buffer[StrLen(Buffer)-1] = CHAR_NULL;
    142   }
    143 
    144   return (Status);
    145 }
    146 
    147 
    148 /**
    149   Function to read a single line using StdIn from a SHELL_FILE_HANDLE. The \n is not included in the returned
    150   buffer.  The returned buffer must be callee freed.
    151 
    152   If the position upon start is 0, then the Ascii Boolean will be set.  This should be
    153   maintained and not changed for all operations with the same file.
    154 
    155   @param[in]       Handle        SHELL_FILE_HANDLE to read from.
    156 
    157   @return                        The line of text from the file.
    158   @retval NULL                   There was not enough memory available.
    159 
    160   @sa ShellFileHandleReadLine
    161 **/
    162 CHAR16*
    163 EFIAPI
    164 ParseReturnStdInLine (
    165   IN SHELL_FILE_HANDLE Handle
    166   )
    167 {
    168   CHAR16          *RetVal;
    169   UINTN           Size;
    170   EFI_STATUS      Status;
    171 
    172   Size   = 0;
    173   RetVal = NULL;
    174 
    175   Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE);
    176   if (Status == EFI_BUFFER_TOO_SMALL) {
    177     RetVal = AllocateZeroPool(Size);
    178     if (RetVal == NULL) {
    179       return (NULL);
    180     }
    181     Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE);
    182 
    183   }
    184   if (EFI_ERROR(Status) && (RetVal != NULL)) {
    185     FreePool(RetVal);
    186     RetVal = NULL;
    187   }
    188   return (RetVal);
    189 }
    190 
    191 /**
    192   Handle stings for SFO Output with escape character ^ in a string
    193   1. Quotation marks in the string must be escaped by using a ^ character (i.e. ^").
    194   2. The ^ character may be inserted using ^^.
    195 
    196   @param[in]  String  The Unicode NULL-terminated string.
    197 
    198   @retval NewString   The new string handled for SFO.
    199 **/
    200 EFI_STRING
    201 HandleStringWithEscapeCharForParse (
    202   IN      CHAR16  *String
    203   )
    204 {
    205   EFI_STRING  NewStr;
    206   EFI_STRING  StrWalker;
    207   EFI_STRING  ReturnStr;
    208 
    209   if (String == NULL) {
    210     return NULL;
    211   }
    212 
    213   //
    214   // start to parse the input string.
    215   //
    216   NewStr = AllocateZeroPool (StrSize (String));
    217   if (NewStr == NULL) {
    218     return NULL;
    219   }
    220   ReturnStr = NewStr;
    221   StrWalker = String;
    222   while (*StrWalker != CHAR_NULL) {
    223     if (*StrWalker == L'^' && (*(StrWalker + 1) == L'^' || *(StrWalker + 1) == L'"')) {
    224       *NewStr = *(StrWalker + 1);
    225       StrWalker++;
    226     } else {
    227       *NewStr = *StrWalker;
    228     }
    229     StrWalker++;
    230     NewStr++;
    231   }
    232 
    233   return ReturnStr;
    234 }
    235 
    236 
    237 /**
    238   Do the actual parsing of the file.  the file should be SFO output from a
    239   shell command or a similar format.
    240 
    241   @param[in] FileName               The filename to open.
    242   @param[in] TableName              The name of the table to find.
    243   @param[in] ColumnIndex            The column number to get.
    244   @param[in] TableNameInstance      Which instance of the table to get (row).
    245   @param[in] ShellCommandInstance   Which instance of the command to get.
    246   @param[in] StreamingUnicode       Indicates Input file is StdIn Unicode streaming data or not
    247 
    248   @retval SHELL_NOT_FOUND     The requested instance was not found.
    249   @retval SHELL_SUCCESS       The operation was successful.
    250 **/
    251 SHELL_STATUS
    252 EFIAPI
    253 PerformParsing(
    254   IN CONST CHAR16 *FileName,
    255   IN CONST CHAR16 *TableName,
    256   IN CONST UINTN  ColumnIndex,
    257   IN CONST UINTN  TableNameInstance,
    258   IN CONST UINTN  ShellCommandInstance,
    259   IN BOOLEAN      StreamingUnicode
    260   )
    261 {
    262   SHELL_FILE_HANDLE FileHandle;
    263   EFI_STATUS        Status;
    264   BOOLEAN           Ascii;
    265   UINTN             LoopVariable;
    266   UINTN             ColumnLoop;
    267   CHAR16            *TempLine;
    268   CHAR16            *ColumnPointer;
    269   SHELL_STATUS      ShellStatus;
    270   CHAR16            *TempSpot;
    271   CHAR16            *SfoString;
    272 
    273   ASSERT(FileName   != NULL);
    274   ASSERT(TableName  != NULL);
    275 
    276   ShellStatus       = SHELL_SUCCESS;
    277 
    278   Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
    279   if (EFI_ERROR(Status)) {
    280     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"parse", FileName);
    281     ShellStatus = SHELL_NOT_FOUND;
    282   } else if (!EFI_ERROR (FileHandleIsDirectory (FileHandle))) {
    283     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_FILE), gShellLevel2HiiHandle, L"parse", FileName);
    284     ShellStatus = SHELL_NOT_FOUND;
    285   } else {
    286     for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) {
    287      if (StreamingUnicode) {
    288        TempLine = ParseReturnStdInLine (FileHandle);
    289      } else {
    290        TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
    291      }
    292 
    293       if ((TempLine == NULL) || (*TempLine == CHAR_NULL && StreamingUnicode)) {
    294          break;
    295       }
    296 
    297       //
    298       // Search for "ShellCommand," in the file to start the SFO table
    299       // for a given ShellCommand.  The UEFI Shell spec does not specify
    300       // a space after the comma.
    301       //
    302       if (StrStr (TempLine, L"ShellCommand,") == TempLine) {
    303         LoopVariable++;
    304       }
    305       SHELL_FREE_NON_NULL(TempLine);
    306     }
    307     if (LoopVariable == ShellCommandInstance) {
    308       LoopVariable = 0;
    309       while(1) {
    310         if (StreamingUnicode) {
    311           TempLine = ParseReturnStdInLine (FileHandle);
    312         } else {
    313           TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
    314         }
    315         if (TempLine == NULL
    316             || *TempLine == CHAR_NULL
    317             || StrStr (TempLine, L"ShellCommand,") == TempLine) {
    318           SHELL_FREE_NON_NULL(TempLine);
    319           break;
    320         }
    321         if (StrStr (TempLine, TableName) == TempLine) {
    322           LoopVariable++;
    323           if (LoopVariable == TableNameInstance
    324               || (TableNameInstance == (UINTN)-1)) {
    325             for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) {
    326               ColumnPointer = StrStr (ColumnPointer, L",\"");
    327               if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL){
    328                 ColumnPointer++;
    329               }
    330             }
    331             if (ColumnLoop == ColumnIndex) {
    332               if (ColumnPointer == NULL) {
    333                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index");
    334                 ShellStatus = SHELL_INVALID_PARAMETER;
    335               } else {
    336                 TempSpot = StrStr (ColumnPointer, L",\"");
    337                 if (TempSpot != NULL) {
    338                   *TempSpot = CHAR_NULL;
    339                 }
    340                 while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' '){
    341                   ColumnPointer++;
    342                 }
    343                 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L'\"'){
    344                   ColumnPointer++;
    345                 }
    346                 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[StrLen (ColumnPointer) - 1] == L'\"'){
    347                   ColumnPointer[StrLen (ColumnPointer) - 1] = CHAR_NULL;
    348                 }
    349                 SfoString = HandleStringWithEscapeCharForParse (ColumnPointer);
    350                 if (SfoString != NULL) {
    351                   ShellPrintEx (-1, -1, L"%s\r\n", SfoString);
    352                   SHELL_FREE_NON_NULL (SfoString);
    353                 }
    354               }
    355             }
    356           }
    357         }
    358         SHELL_FREE_NON_NULL(TempLine);
    359       }
    360     }
    361   }
    362   return (ShellStatus);
    363 }
    364 
    365 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
    366   {L"-i", TypeValue},
    367   {L"-s", TypeValue},
    368   {NULL, TypeMax}
    369   };
    370 
    371 /**
    372   Function for 'parse' command.
    373 
    374   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    375   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    376 **/
    377 SHELL_STATUS
    378 EFIAPI
    379 ShellCommandRunParse (
    380   IN EFI_HANDLE        ImageHandle,
    381   IN EFI_SYSTEM_TABLE  *SystemTable
    382   )
    383 {
    384   EFI_STATUS          Status;
    385   LIST_ENTRY          *Package;
    386   CHAR16              *ProblemParam;
    387   CONST CHAR16        *FileName;
    388   CONST CHAR16        *TableName;
    389   CONST CHAR16        *ColumnString;
    390   SHELL_STATUS        ShellStatus;
    391   UINTN               ShellCommandInstance;
    392   UINTN               TableNameInstance;
    393   BOOLEAN             StreamingUnicode;
    394 
    395   ShellStatus      = SHELL_SUCCESS;
    396   ProblemParam     = NULL;
    397   StreamingUnicode = FALSE;
    398 
    399   //
    400   // initialize the shell lib (we must be in non-auto-init...)
    401   //
    402   Status = ShellInitialize();
    403   ASSERT_EFI_ERROR(Status);
    404 
    405   //
    406   // parse the command line
    407   //
    408   Status = ShellCommandLineParseEx (ParamList, &Package, &ProblemParam, TRUE, FALSE);
    409   if (EFI_ERROR(Status)) {
    410     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
    411       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"parse", ProblemParam);
    412       FreePool(ProblemParam);
    413       ShellStatus = SHELL_INVALID_PARAMETER;
    414     } else {
    415       ASSERT(FALSE);
    416     }
    417   } else {
    418     StreamingUnicode = IsStdInDataAvailable ();
    419     if ((!StreamingUnicode && (ShellCommandLineGetCount(Package) < 4)) ||
    420         (ShellCommandLineGetCount(Package) < 3)) {
    421       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"parse");
    422       ShellStatus = SHELL_INVALID_PARAMETER;
    423     } else if ((StreamingUnicode && (ShellCommandLineGetCount(Package) > 3)) ||
    424                 (ShellCommandLineGetCount(Package) > 4)) {
    425       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"parse");
    426       ShellStatus = SHELL_INVALID_PARAMETER;
    427     } else {
    428       if (StreamingUnicode) {
    429         FileName         = L">i";
    430         TableName        = ShellCommandLineGetRawValue(Package, 1);
    431         ColumnString     = ShellCommandLineGetRawValue(Package, 2);
    432       } else {
    433         FileName         = ShellCommandLineGetRawValue(Package, 1);
    434         TableName        = ShellCommandLineGetRawValue(Package, 2);
    435         ColumnString     = ShellCommandLineGetRawValue(Package, 3);
    436       }
    437       if (ShellCommandLineGetValue(Package, L"-i") == NULL) {
    438         TableNameInstance = (UINTN)-1;
    439       } else {
    440         TableNameInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-i"));
    441       }
    442       if (ShellCommandLineGetValue(Package, L"-s") == NULL) {
    443         ShellCommandInstance = 1;
    444       } else {
    445         ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s"));
    446       }
    447 
    448       ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode);
    449     }
    450   }
    451 
    452   //
    453   // free the command line package
    454   //
    455   ShellCommandLineFreeVarList (Package);
    456 
    457   return (ShellStatus);
    458 }
    459 
    460