• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
IsStdInDataAvailable(VOID)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
ShellFileHandleReadStdInLine(IN SHELL_FILE_HANDLE Handle,IN OUT CHAR16 * Buffer,IN OUT UINTN * Size,IN BOOLEAN Truncate)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
ParseReturnStdInLine(IN SHELL_FILE_HANDLE Handle)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
HandleStringWithEscapeCharForParse(IN CHAR16 * 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
PerformParsing(IN CONST CHAR16 * FileName,IN CONST CHAR16 * TableName,IN CONST UINTN ColumnIndex,IN CONST UINTN TableNameInstance,IN CONST UINTN ShellCommandInstance,IN BOOLEAN StreamingUnicode)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
ShellCommandRunParse(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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