2 Main file for Parse shell level 2 function.
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
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.
16 #include "UefiShellLevel2CommandsLib.h"
19 Check if data is coming from StdIn output.
23 @retval TRUE StdIn stream data available to parse
24 @retval FALSE StdIn stream data is not available to parse.
27 IsStdInDataAvailable (
31 SHELL_FILE_HANDLE FileHandle
;
35 UINT64 OriginalFilePosition
;
39 OriginalFilePosition
= 0;
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
))) {
48 gEfiShellProtocol
->SetFilePosition(FileHandle
, OriginalFilePosition
);
51 if (FileHandle
== NULL
) {
59 Function to read a single line (up to but not including the \n) using StdIn data from a SHELL_FILE_HANDLE.
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.
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.
73 @retval EFI_SUCCESS The operation was successful. The line is stored in
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.
81 ShellFileHandleReadStdInLine(
82 IN SHELL_FILE_HANDLE Handle
,
83 IN OUT CHAR16
*Buffer
,
92 UINT64 OriginalFilePosition
;
98 return (EFI_INVALID_PARAMETER
);
100 if (Buffer
== NULL
) {
105 gEfiShellProtocol
->GetFilePosition (Handle
, &OriginalFilePosition
);
107 for (CountSoFar
= 0;;CountSoFar
++){
109 CharSize
= sizeof(CHAR16
);
110 Status
= gEfiShellProtocol
->ReadFile (Handle
, &CharSize
, &CharBuffer
);
111 if ( EFI_ERROR(Status
)
113 || (CharBuffer
== L
'\n')
118 // if we have space save it...
120 if ((CountSoFar
+1)*sizeof(CHAR16
) < *Size
){
121 ASSERT(Buffer
!= NULL
);
122 ((CHAR16
*)Buffer
)[CountSoFar
] = CharBuffer
;
123 ((CHAR16
*)Buffer
)[CountSoFar
+1] = CHAR_NULL
;
128 // if we ran out of space tell when...
130 if ((CountSoFar
+1)*sizeof(CHAR16
) > *Size
){
131 *Size
= (CountSoFar
+1)*sizeof(CHAR16
);
133 gEfiShellProtocol
->SetFilePosition(Handle
, OriginalFilePosition
);
135 DEBUG((DEBUG_WARN
, "The line was truncated in ShellFileHandleReadLine"));
137 return (EFI_BUFFER_TOO_SMALL
);
139 while(Buffer
[StrLen(Buffer
)-1] == L
'\r') {
140 Buffer
[StrLen(Buffer
)-1] = CHAR_NULL
;
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.
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.
154 @param[in] Handle SHELL_FILE_HANDLE to read from.
156 @return The line of text from the file.
157 @retval NULL There was not enough memory available.
159 @sa ShellFileHandleReadLine
162 ParseReturnStdInLine (
163 IN SHELL_FILE_HANDLE Handle
173 Status
= ShellFileHandleReadStdInLine (Handle
, RetVal
, &Size
, FALSE
);
174 if (Status
== EFI_BUFFER_TOO_SMALL
) {
175 RetVal
= AllocateZeroPool(Size
);
176 if (RetVal
== NULL
) {
179 Status
= ShellFileHandleReadStdInLine (Handle
, RetVal
, &Size
, FALSE
);
182 if (EFI_ERROR(Status
) && (RetVal
!= NULL
)) {
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 ^^.
194 @param[in] String The Unicode NULL-terminated string.
196 @retval NewString The new string handled for SFO.
199 HandleStringWithEscapeCharForParse (
204 EFI_STRING StrWalker
;
205 EFI_STRING ReturnStr
;
207 if (String
== NULL
) {
212 // start to parse the input string.
214 NewStr
= AllocateZeroPool (StrSize (String
));
215 if (NewStr
== NULL
) {
220 while (*StrWalker
!= CHAR_NULL
) {
221 if (*StrWalker
== L
'^' && (*(StrWalker
+ 1) == L
'^' || *(StrWalker
+ 1) == L
'"')) {
222 *NewStr
= *(StrWalker
+ 1);
225 *NewStr
= *StrWalker
;
236 Do the actual parsing of the file. the file should be SFO output from a
237 shell command or a similar format.
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
246 @retval SHELL_NOT_FOUND The requested instance was not found.
247 @retval SHELL_SUCCESS The operation was successful.
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
259 SHELL_FILE_HANDLE FileHandle
;
265 CHAR16
*ColumnPointer
;
266 SHELL_STATUS ShellStatus
;
270 ASSERT(FileName
!= NULL
);
271 ASSERT(TableName
!= NULL
);
273 ShellStatus
= SHELL_SUCCESS
;
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
;
283 for (LoopVariable
= 0 ; LoopVariable
< ShellCommandInstance
&& !ShellFileHandleEof(FileHandle
);) {
284 if (StreamingUnicode
) {
285 TempLine
= ParseReturnStdInLine (FileHandle
);
287 TempLine
= ShellFileHandleReturnLine (FileHandle
, &Ascii
);
290 if ((TempLine
== NULL
) || (*TempLine
== CHAR_NULL
&& StreamingUnicode
)) {
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.
299 if (StrStr (TempLine
, L
"ShellCommand,") == TempLine
) {
302 SHELL_FREE_NON_NULL(TempLine
);
304 if (LoopVariable
== ShellCommandInstance
) {
307 if (StreamingUnicode
) {
308 TempLine
= ParseReturnStdInLine (FileHandle
);
310 TempLine
= ShellFileHandleReturnLine (FileHandle
, &Ascii
);
313 || *TempLine
== CHAR_NULL
314 || StrStr (TempLine
, L
"ShellCommand,") == TempLine
) {
315 SHELL_FREE_NON_NULL(TempLine
);
318 if (StrStr (TempLine
, TableName
) == TempLine
) {
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
){
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
;
333 TempSpot
= StrStr (ColumnPointer
, L
",\"");
334 if (TempSpot
!= NULL
) {
335 *TempSpot
= CHAR_NULL
;
337 while (ColumnPointer
!= NULL
&& *ColumnPointer
!= CHAR_NULL
&& ColumnPointer
[0] == L
' '){
340 if (ColumnPointer
!= NULL
&& *ColumnPointer
!= CHAR_NULL
&& ColumnPointer
[0] == L
'\"'){
343 if (ColumnPointer
!= NULL
&& *ColumnPointer
!= CHAR_NULL
&& ColumnPointer
[StrLen (ColumnPointer
) - 1] == L
'\"'){
344 ColumnPointer
[StrLen (ColumnPointer
) - 1] = CHAR_NULL
;
346 SfoString
= HandleStringWithEscapeCharForParse (ColumnPointer
);
347 if (SfoString
!= NULL
) {
348 ShellPrintEx (-1, -1, L
"%s\r\n", SfoString
);
349 SHELL_FREE_NON_NULL (SfoString
);
355 SHELL_FREE_NON_NULL(TempLine
);
359 return (ShellStatus
);
362 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
369 Function for 'parse' command.
371 @param[in] ImageHandle Handle to the Image (NULL if Internal).
372 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
376 ShellCommandRunParse (
377 IN EFI_HANDLE ImageHandle
,
378 IN EFI_SYSTEM_TABLE
*SystemTable
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
;
392 ShellStatus
= SHELL_SUCCESS
;
394 StreamingUnicode
= FALSE
;
397 // initialize the shell lib (we must be in non-auto-init...)
399 Status
= ShellInitialize();
400 ASSERT_EFI_ERROR(Status
);
403 // parse the command line
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
;
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
;
425 if (StreamingUnicode
) {
427 TableName
= ShellCommandLineGetRawValue(Package
, 1);
428 ColumnString
= ShellCommandLineGetRawValue(Package
, 2);
430 FileName
= ShellCommandLineGetRawValue(Package
, 1);
431 TableName
= ShellCommandLineGetRawValue(Package
, 2);
432 ColumnString
= ShellCommandLineGetRawValue(Package
, 3);
434 if (ShellCommandLineGetValue(Package
, L
"-i") == NULL
) {
435 TableNameInstance
= (UINTN
)-1;
437 TableNameInstance
= ShellStrToUintn(ShellCommandLineGetValue(Package
, L
"-i"));
439 if (ShellCommandLineGetValue(Package
, L
"-s") == NULL
) {
440 ShellCommandInstance
= 1;
442 ShellCommandInstance
= ShellStrToUintn(ShellCommandLineGetValue(Package
, L
"-s"));
445 ShellStatus
= PerformParsing(FileName
, TableName
, ShellStrToUintn(ColumnString
), TableNameInstance
, ShellCommandInstance
, StreamingUnicode
);
450 // free the command line package
452 ShellCommandLineFreeVarList (Package
);
454 return (ShellStatus
);