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