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 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "UefiShellLevel2CommandsLib.h"
11
12 /**
13 Check if data is coming from StdIn output.
14
15 @param[in] None
16
17 @retval TRUE StdIn stream data available to parse
18 @retval FALSE StdIn stream data is not available to parse.
19 **/
20 BOOLEAN
IsStdInDataAvailable(VOID)21 IsStdInDataAvailable (
22 VOID
23 )
24 {
25 SHELL_FILE_HANDLE FileHandle;
26 EFI_STATUS Status;
27 CHAR16 CharBuffer;
28 UINTN CharSize;
29 UINT64 OriginalFilePosition;
30
31 Status = EFI_SUCCESS;
32 FileHandle = NULL;
33 OriginalFilePosition = 0;
34
35 if (ShellOpenFileByName (L">i", &FileHandle, EFI_FILE_MODE_READ, 0) == EFI_SUCCESS) {
36 CharSize = sizeof(CHAR16);
37 gEfiShellProtocol->GetFilePosition (FileHandle, &OriginalFilePosition);
38 Status = gEfiShellProtocol->ReadFile (FileHandle, &CharSize, &CharBuffer);
39 if (EFI_ERROR (Status) || (CharSize != sizeof(CHAR16))) {
40 return FALSE;
41 }
42 gEfiShellProtocol->SetFilePosition(FileHandle, OriginalFilePosition);
43 }
44
45 if (FileHandle == NULL) {
46 return FALSE;
47 } else {
48 return TRUE;
49 }
50 }
51
52 /**
53 Handle stings for SFO Output with escape character ^ in a string
54 1. Quotation marks in the string must be escaped by using a ^ character (i.e. ^").
55 2. The ^ character may be inserted using ^^.
56
57 @param[in] String The Unicode NULL-terminated string.
58
59 @retval NewString The new string handled for SFO.
60 **/
61 EFI_STRING
HandleStringWithEscapeCharForParse(IN CHAR16 * String)62 HandleStringWithEscapeCharForParse (
63 IN CHAR16 *String
64 )
65 {
66 EFI_STRING NewStr;
67 EFI_STRING StrWalker;
68 EFI_STRING ReturnStr;
69
70 if (String == NULL) {
71 return NULL;
72 }
73
74 //
75 // start to parse the input string.
76 //
77 NewStr = AllocateZeroPool (StrSize (String));
78 if (NewStr == NULL) {
79 return NULL;
80 }
81 ReturnStr = NewStr;
82 StrWalker = String;
83 while (*StrWalker != CHAR_NULL) {
84 if (*StrWalker == L'^' && (*(StrWalker + 1) == L'^' || *(StrWalker + 1) == L'"')) {
85 *NewStr = *(StrWalker + 1);
86 StrWalker++;
87 } else {
88 *NewStr = *StrWalker;
89 }
90 StrWalker++;
91 NewStr++;
92 }
93
94 return ReturnStr;
95 }
96
97
98 /**
99 Do the actual parsing of the file. the file should be SFO output from a
100 shell command or a similar format.
101
102 @param[in] FileName The filename to open.
103 @param[in] TableName The name of the table to find.
104 @param[in] ColumnIndex The column number to get.
105 @param[in] TableNameInstance Which instance of the table to get (row).
106 @param[in] ShellCommandInstance Which instance of the command to get.
107 @param[in] StreamingUnicode Indicates Input file is StdIn Unicode streaming data or not
108
109 @retval SHELL_NOT_FOUND The requested instance was not found.
110 @retval SHELL_SUCCESS The operation was successful.
111 **/
112 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)113 PerformParsing(
114 IN CONST CHAR16 *FileName,
115 IN CONST CHAR16 *TableName,
116 IN CONST UINTN ColumnIndex,
117 IN CONST UINTN TableNameInstance,
118 IN CONST UINTN ShellCommandInstance,
119 IN BOOLEAN StreamingUnicode
120 )
121 {
122 SHELL_FILE_HANDLE FileHandle;
123 EFI_STATUS Status;
124 BOOLEAN Ascii;
125 UINTN LoopVariable;
126 UINTN ColumnLoop;
127 CHAR16 *TempLine;
128 CHAR16 *ColumnPointer;
129 SHELL_STATUS ShellStatus;
130 CHAR16 *TempSpot;
131 CHAR16 *SfoString;
132
133 ASSERT(FileName != NULL);
134 ASSERT(TableName != NULL);
135
136 ShellStatus = SHELL_SUCCESS;
137
138 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);
139 if (EFI_ERROR(Status)) {
140 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"parse", FileName);
141 ShellStatus = SHELL_NOT_FOUND;
142 } else if (!EFI_ERROR (FileHandleIsDirectory (FileHandle))) {
143 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_FILE), gShellLevel2HiiHandle, L"parse", FileName);
144 ShellStatus = SHELL_NOT_FOUND;
145 } else {
146 for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) {
147 TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
148
149 if ((TempLine == NULL) || (*TempLine == CHAR_NULL && StreamingUnicode)) {
150 break;
151 }
152
153 //
154 // Search for "ShellCommand," in the file to start the SFO table
155 // for a given ShellCommand. The UEFI Shell spec does not specify
156 // a space after the comma.
157 //
158 if (StrStr (TempLine, L"ShellCommand,") == TempLine) {
159 LoopVariable++;
160 }
161 SHELL_FREE_NON_NULL(TempLine);
162 }
163 if (LoopVariable == ShellCommandInstance) {
164 LoopVariable = 0;
165 while(1) {
166 TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii);
167 if (TempLine == NULL
168 || *TempLine == CHAR_NULL
169 || StrStr (TempLine, L"ShellCommand,") == TempLine) {
170 SHELL_FREE_NON_NULL(TempLine);
171 break;
172 }
173 if (StrStr (TempLine, TableName) == TempLine) {
174 LoopVariable++;
175 if (LoopVariable == TableNameInstance
176 || (TableNameInstance == (UINTN)-1)) {
177 for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) {
178 ColumnPointer = StrStr (ColumnPointer, L",\"");
179 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL){
180 ColumnPointer++;
181 }
182 }
183 if (ColumnLoop == ColumnIndex) {
184 if (ColumnPointer == NULL) {
185 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index");
186 ShellStatus = SHELL_INVALID_PARAMETER;
187 } else {
188 TempSpot = StrStr (ColumnPointer, L",\"");
189 if (TempSpot != NULL) {
190 *TempSpot = CHAR_NULL;
191 }
192 while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' '){
193 ColumnPointer++;
194 }
195 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L'\"'){
196 ColumnPointer++;
197 }
198 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[StrLen (ColumnPointer) - 1] == L'\"'){
199 ColumnPointer[StrLen (ColumnPointer) - 1] = CHAR_NULL;
200 }
201 SfoString = HandleStringWithEscapeCharForParse (ColumnPointer);
202 if (SfoString != NULL) {
203 ShellPrintEx (-1, -1, L"%s\r\n", SfoString);
204 SHELL_FREE_NON_NULL (SfoString);
205 }
206 }
207 }
208 }
209 }
210 SHELL_FREE_NON_NULL(TempLine);
211 }
212 }
213 }
214 return (ShellStatus);
215 }
216
217 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
218 {L"-i", TypeValue},
219 {L"-s", TypeValue},
220 {NULL, TypeMax}
221 };
222
223 /**
224 Function for 'parse' command.
225
226 @param[in] ImageHandle Handle to the Image (NULL if Internal).
227 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
228 **/
229 SHELL_STATUS
230 EFIAPI
ShellCommandRunParse(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)231 ShellCommandRunParse (
232 IN EFI_HANDLE ImageHandle,
233 IN EFI_SYSTEM_TABLE *SystemTable
234 )
235 {
236 EFI_STATUS Status;
237 LIST_ENTRY *Package;
238 CHAR16 *ProblemParam;
239 CONST CHAR16 *FileName;
240 CONST CHAR16 *TableName;
241 CONST CHAR16 *ColumnString;
242 SHELL_STATUS ShellStatus;
243 UINTN ShellCommandInstance;
244 UINTN TableNameInstance;
245 BOOLEAN StreamingUnicode;
246
247 ShellStatus = SHELL_SUCCESS;
248 ProblemParam = NULL;
249 StreamingUnicode = FALSE;
250
251 //
252 // initialize the shell lib (we must be in non-auto-init...)
253 //
254 Status = ShellInitialize();
255 ASSERT_EFI_ERROR(Status);
256
257 //
258 // parse the command line
259 //
260 Status = ShellCommandLineParseEx (ParamList, &Package, &ProblemParam, TRUE, FALSE);
261 if (EFI_ERROR(Status)) {
262 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
263 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"parse", ProblemParam);
264 FreePool(ProblemParam);
265 ShellStatus = SHELL_INVALID_PARAMETER;
266 } else {
267 ASSERT(FALSE);
268 }
269 } else {
270 StreamingUnicode = IsStdInDataAvailable ();
271 if ((!StreamingUnicode && (ShellCommandLineGetCount(Package) < 4)) ||
272 (ShellCommandLineGetCount(Package) < 3)) {
273 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"parse");
274 ShellStatus = SHELL_INVALID_PARAMETER;
275 } else if ((StreamingUnicode && (ShellCommandLineGetCount(Package) > 3)) ||
276 (ShellCommandLineGetCount(Package) > 4)) {
277 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"parse");
278 ShellStatus = SHELL_INVALID_PARAMETER;
279 } else {
280 if (StreamingUnicode) {
281 FileName = L">i";
282 TableName = ShellCommandLineGetRawValue(Package, 1);
283 ColumnString = ShellCommandLineGetRawValue(Package, 2);
284 } else {
285 FileName = ShellCommandLineGetRawValue(Package, 1);
286 TableName = ShellCommandLineGetRawValue(Package, 2);
287 ColumnString = ShellCommandLineGetRawValue(Package, 3);
288 }
289 if (ShellCommandLineGetValue(Package, L"-i") == NULL) {
290 TableNameInstance = (UINTN)-1;
291 } else {
292 TableNameInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-i"));
293 }
294 if (ShellCommandLineGetValue(Package, L"-s") == NULL) {
295 ShellCommandInstance = 1;
296 } else {
297 ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s"));
298 }
299
300 ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode);
301 }
302 }
303
304 //
305 // free the command line package
306 //
307 ShellCommandLineFreeVarList (Package);
308
309 return (ShellStatus);
310 }
311
312