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