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