]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Parse.c
ShellPkg/UefiShellLevel2CommandsLib: rebase to ARRAY_SIZE()
[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
8fcf74a8 5 Copyright (c) 2009 - 2012, 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
58/**\r
59 Function to read a single line (up to but not including the \n) using StdIn data from a SHELL_FILE_HANDLE.\r
60\r
61 If the position upon start is 0, then the Ascii Boolean will be set. This should be\r
62 maintained and not changed for all operations with the same file.\r
63\r
64 @param[in] Handle SHELL_FILE_HANDLE to read from.\r
65 @param[in, out] Buffer The pointer to buffer to read into.\r
66 @param[in, out] Size The pointer to number of bytes in Buffer.\r
67 @param[in] Truncate If the buffer is large enough, this has no effect.\r
68 If the buffer is is too small and Truncate is TRUE,\r
69 the line will be truncated.\r
70 If the buffer is is too small and Truncate is FALSE,\r
71 then no read will occur.\r
72\r
73 @retval EFI_SUCCESS The operation was successful. The line is stored in\r
74 Buffer.\r
75 @retval EFI_INVALID_PARAMETER Handle was NULL.\r
76 @retval EFI_INVALID_PARAMETER Size was NULL.\r
77 @retval EFI_BUFFER_TOO_SMALL Size was not large enough to store the line.\r
78 Size was updated to the minimum space required.\r
79**/\r
80EFI_STATUS\r
421fbf99
TS
81ShellFileHandleReadStdInLine(\r
82 IN SHELL_FILE_HANDLE Handle,\r
83 IN OUT CHAR16 *Buffer,\r
84 IN OUT UINTN *Size,\r
85 IN BOOLEAN Truncate\r
86 )\r
87{\r
88 EFI_STATUS Status;\r
89 CHAR16 CharBuffer;\r
90 UINTN CharSize;\r
91 UINTN CountSoFar;\r
92 UINT64 OriginalFilePosition;\r
93\r
94\r
95 if (Handle == NULL\r
96 ||Size == NULL\r
97 ){\r
98 return (EFI_INVALID_PARAMETER);\r
99 }\r
100 if (Buffer == NULL) {\r
101 ASSERT(*Size == 0);\r
102 } else {\r
103 *Buffer = CHAR_NULL;\r
104 }\r
105 gEfiShellProtocol->GetFilePosition (Handle, &OriginalFilePosition);\r
106\r
107 for (CountSoFar = 0;;CountSoFar++){\r
108 CharBuffer = 0;\r
109 CharSize = sizeof(CHAR16);\r
110 Status = gEfiShellProtocol->ReadFile (Handle, &CharSize, &CharBuffer);\r
111 if ( EFI_ERROR(Status)\r
112 || CharSize == 0\r
113 || (CharBuffer == L'\n')\r
114 ){\r
115 break;\r
116 }\r
117 //\r
118 // if we have space save it...\r
119 //\r
120 if ((CountSoFar+1)*sizeof(CHAR16) < *Size){\r
121 ASSERT(Buffer != NULL);\r
122 ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
123 ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
124 }\r
125 }\r
126\r
127 //\r
128 // if we ran out of space tell when...\r
129 //\r
130 if ((CountSoFar+1)*sizeof(CHAR16) > *Size){\r
131 *Size = (CountSoFar+1)*sizeof(CHAR16);\r
132 if (!Truncate) {\r
133 gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
134 } else {\r
135 DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
136 }\r
137 return (EFI_BUFFER_TOO_SMALL);\r
138 }\r
139 while(Buffer[StrLen(Buffer)-1] == L'\r') {\r
140 Buffer[StrLen(Buffer)-1] = CHAR_NULL;\r
141 }\r
142\r
143 return (Status);\r
144}\r
145\r
146\r
147/**\r
148 Function to read a single line using StdIn from a SHELL_FILE_HANDLE. The \n is not included in the returned\r
149 buffer. The returned buffer must be callee freed.\r
150\r
151 If the position upon start is 0, then the Ascii Boolean will be set. This should be\r
152 maintained and not changed for all operations with the same file.\r
153\r
154 @param[in] Handle SHELL_FILE_HANDLE to read from.\r
155\r
156 @return The line of text from the file.\r
157 @retval NULL There was not enough memory available.\r
158\r
159 @sa ShellFileHandleReadLine\r
160**/\r
161CHAR16*\r
421fbf99
TS
162ParseReturnStdInLine (\r
163 IN SHELL_FILE_HANDLE Handle\r
164 )\r
165{\r
166 CHAR16 *RetVal;\r
167 UINTN Size;\r
168 EFI_STATUS Status;\r
169\r
170 Size = 0;\r
171 RetVal = NULL;\r
172\r
173 Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE);\r
174 if (Status == EFI_BUFFER_TOO_SMALL) {\r
175 RetVal = AllocateZeroPool(Size);\r
176 if (RetVal == NULL) {\r
177 return (NULL);\r
178 }\r
179 Status = ShellFileHandleReadStdInLine (Handle, RetVal, &Size, FALSE);\r
180\r
181 }\r
182 if (EFI_ERROR(Status) && (RetVal != NULL)) {\r
183 FreePool(RetVal);\r
184 RetVal = NULL;\r
185 }\r
186 return (RetVal);\r
187}\r
188\r
307f2ce4
TS
189/**\r
190 Handle stings for SFO Output with escape character ^ in a string\r
4fe19afe 191 1. Quotation marks in the string must be escaped by using a ^ character (i.e. ^"). \r
307f2ce4
TS
192 2. The ^ character may be inserted using ^^.\r
193\r
194 @param[in] String The Unicode NULL-terminated string.\r
195 \r
196 @retval NewString The new string handled for SFO.\r
197**/\r
198EFI_STRING\r
199HandleStringWithEscapeCharForParse (\r
200 IN CHAR16 *String\r
201 )\r
202{\r
203 EFI_STRING NewStr;\r
204 EFI_STRING StrWalker;\r
205 EFI_STRING ReturnStr;\r
206\r
207 if (String == NULL) {\r
208 return NULL;\r
209 }\r
210 \r
211 //\r
212 // start to parse the input string.\r
213 //\r
214 NewStr = AllocateZeroPool (StrSize (String));\r
215 if (NewStr == NULL) {\r
216 return NULL;\r
217 }\r
218 ReturnStr = NewStr;\r
219 StrWalker = String;\r
220 while (*StrWalker != CHAR_NULL) {\r
221 if (*StrWalker == L'^' && (*(StrWalker + 1) == L'^' || *(StrWalker + 1) == L'"')) {\r
222 *NewStr = *(StrWalker + 1);\r
223 StrWalker++;\r
224 } else {\r
225 *NewStr = *StrWalker;\r
226 }\r
227 StrWalker++;\r
228 NewStr++;\r
229 }\r
230 \r
231 return ReturnStr;\r
232}\r
233\r
234\r
b54fd049 235/**\r
236 Do the actual parsing of the file. the file should be SFO output from a \r
237 shell command or a similar format.\r
238\r
239 @param[in] FileName The filename to open.\r
240 @param[in] TableName The name of the table to find.\r
241 @param[in] ColumnIndex The column number to get.\r
242 @param[in] TableNameInstance Which instance of the table to get (row).\r
243 @param[in] ShellCommandInstance Which instance of the command to get.\r
421fbf99 244 @param[in] StreamingUnicode Indicates Input file is StdIn Unicode streaming data or not\r
b54fd049 245\r
246 @retval SHELL_NOT_FOUND The requested instance was not found.\r
247 @retval SHELL_SUCCESS The operation was successful.\r
248**/\r
a405b86d 249SHELL_STATUS\r
a405b86d 250PerformParsing(\r
251 IN CONST CHAR16 *FileName,\r
252 IN CONST CHAR16 *TableName,\r
253 IN CONST UINTN ColumnIndex,\r
254 IN CONST UINTN TableNameInstance,\r
421fbf99
TS
255 IN CONST UINTN ShellCommandInstance,\r
256 IN BOOLEAN StreamingUnicode\r
a405b86d 257 )\r
258{\r
259 SHELL_FILE_HANDLE FileHandle;\r
260 EFI_STATUS Status;\r
261 BOOLEAN Ascii;\r
262 UINTN LoopVariable;\r
263 UINTN ColumnLoop;\r
264 CHAR16 *TempLine;\r
265 CHAR16 *ColumnPointer;\r
266 SHELL_STATUS ShellStatus;\r
267 CHAR16 *TempSpot;\r
307f2ce4 268 CHAR16 *SfoString;\r
a405b86d 269\r
270 ASSERT(FileName != NULL);\r
271 ASSERT(TableName != NULL);\r
272\r
273 ShellStatus = SHELL_SUCCESS;\r
274\r
275 Status = ShellOpenFileByName(FileName, &FileHandle, EFI_FILE_MODE_READ, 0);\r
276 if (EFI_ERROR(Status)) {\r
099e8ff5 277 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"parse", FileName); \r
a405b86d 278 ShellStatus = SHELL_NOT_FOUND;\r
78d42190 279 } else if (!EFI_ERROR (FileHandleIsDirectory (FileHandle))) {\r
099e8ff5 280 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_FILE), gShellLevel2HiiHandle, L"parse", FileName); \r
78d42190 281 ShellStatus = SHELL_NOT_FOUND;\r
a405b86d 282 } else {\r
283 for (LoopVariable = 0 ; LoopVariable < ShellCommandInstance && !ShellFileHandleEof(FileHandle);) {\r
421fbf99
TS
284 if (StreamingUnicode) {\r
285 TempLine = ParseReturnStdInLine (FileHandle);\r
286 } else {\r
287 TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii); \r
288 }\r
289\r
4fe19afe 290 if ((TempLine == NULL) || (*TempLine == CHAR_NULL && StreamingUnicode)) {\r
421fbf99 291 break;\r
a405b86d 292 }\r
78d42190
CP
293\r
294 //\r
295 // Search for "ShellCommand," in the file to start the SFO table\r
296 // for a given ShellCommand. The UEFI Shell spec does not specify\r
297 // a space after the comma.\r
298 //\r
299 if (StrStr (TempLine, L"ShellCommand,") == TempLine) {\r
a405b86d 300 LoopVariable++;\r
301 }\r
302 SHELL_FREE_NON_NULL(TempLine);\r
303 }\r
304 if (LoopVariable == ShellCommandInstance) {\r
305 LoopVariable = 0;\r
306 while(1) {\r
421fbf99
TS
307 if (StreamingUnicode) {\r
308 TempLine = ParseReturnStdInLine (FileHandle);\r
309 } else {\r
310 TempLine = ShellFileHandleReturnLine (FileHandle, &Ascii); \r
311 }\r
78d42190
CP
312 if (TempLine == NULL\r
313 || *TempLine == CHAR_NULL\r
314 || StrStr (TempLine, L"ShellCommand,") == TempLine) {\r
a405b86d 315 SHELL_FREE_NON_NULL(TempLine);\r
316 break;\r
317 }\r
78d42190 318 if (StrStr (TempLine, TableName) == TempLine) {\r
a405b86d 319 LoopVariable++;\r
78d42190
CP
320 if (LoopVariable == TableNameInstance\r
321 || (TableNameInstance == (UINTN)-1)) {\r
322 for (ColumnLoop = 1, ColumnPointer = TempLine; ColumnLoop < ColumnIndex && ColumnPointer != NULL && *ColumnPointer != CHAR_NULL; ColumnLoop++) {\r
76c94bb2 323 ColumnPointer = StrStr (ColumnPointer, L",\"");\r
78d42190 324 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL){\r
8fcf74a8 325 ColumnPointer++;\r
326 }\r
78d42190
CP
327 }\r
328 if (ColumnLoop == ColumnIndex) {\r
329 if (ColumnPointer == NULL) {\r
421fbf99 330 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"parse", L"Column Index"); \r
78d42190
CP
331 ShellStatus = SHELL_INVALID_PARAMETER;\r
332 } else {\r
76c94bb2 333 TempSpot = StrStr (ColumnPointer, L",\"");\r
78d42190
CP
334 if (TempSpot != NULL) {\r
335 *TempSpot = CHAR_NULL;\r
336 }\r
337 while (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L' '){\r
338 ColumnPointer++;\r
339 }\r
340 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[0] == L'\"'){\r
341 ColumnPointer++;\r
342 }\r
343 if (ColumnPointer != NULL && *ColumnPointer != CHAR_NULL && ColumnPointer[StrLen (ColumnPointer) - 1] == L'\"'){\r
344 ColumnPointer[StrLen (ColumnPointer) - 1] = CHAR_NULL;\r
345 }\r
307f2ce4
TS
346 SfoString = HandleStringWithEscapeCharForParse (ColumnPointer);\r
347 if (SfoString != NULL) {\r
348 ShellPrintEx (-1, -1, L"%s\r\n", SfoString);\r
349 SHELL_FREE_NON_NULL (SfoString);\r
350 }\r
78d42190 351 }\r
8fcf74a8 352 }\r
a405b86d 353 }\r
354 }\r
355 SHELL_FREE_NON_NULL(TempLine);\r
356 }\r
357 }\r
358 }\r
359 return (ShellStatus);\r
360}\r
361\r
362STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
363 {L"-i", TypeValue},\r
364 {L"-s", TypeValue},\r
365 {NULL, TypeMax}\r
366 };\r
367\r
368/**\r
369 Function for 'parse' command.\r
370\r
371 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
372 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
373**/\r
374SHELL_STATUS\r
375EFIAPI\r
376ShellCommandRunParse (\r
377 IN EFI_HANDLE ImageHandle,\r
378 IN EFI_SYSTEM_TABLE *SystemTable\r
379 )\r
380{\r
381 EFI_STATUS Status;\r
382 LIST_ENTRY *Package;\r
383 CHAR16 *ProblemParam;\r
384 CONST CHAR16 *FileName;\r
385 CONST CHAR16 *TableName;\r
386 CONST CHAR16 *ColumnString;\r
387 SHELL_STATUS ShellStatus;\r
388 UINTN ShellCommandInstance;\r
389 UINTN TableNameInstance;\r
421fbf99 390 BOOLEAN StreamingUnicode;\r
a405b86d 391\r
421fbf99
TS
392 ShellStatus = SHELL_SUCCESS;\r
393 ProblemParam = NULL;\r
394 StreamingUnicode = FALSE;\r
a405b86d 395\r
396 //\r
397 // initialize the shell lib (we must be in non-auto-init...)\r
398 //\r
399 Status = ShellInitialize();\r
400 ASSERT_EFI_ERROR(Status);\r
401\r
402 //\r
403 // parse the command line\r
404 //\r
421fbf99 405 Status = ShellCommandLineParseEx (ParamList, &Package, &ProblemParam, TRUE, FALSE);\r
a405b86d 406 if (EFI_ERROR(Status)) {\r
407 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
099e8ff5 408 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"parse", ProblemParam); \r
a405b86d 409 FreePool(ProblemParam);\r
410 ShellStatus = SHELL_INVALID_PARAMETER;\r
411 } else {\r
412 ASSERT(FALSE);\r
413 }\r
414 } else {\r
421fbf99
TS
415 StreamingUnicode = IsStdInDataAvailable ();\r
416 if ((!StreamingUnicode && (ShellCommandLineGetCount(Package) < 4)) ||\r
417 (ShellCommandLineGetCount(Package) < 3)) {\r
099e8ff5 418 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"parse"); \r
a405b86d 419 ShellStatus = SHELL_INVALID_PARAMETER;\r
421fbf99
TS
420 } else if ((StreamingUnicode && (ShellCommandLineGetCount(Package) > 3)) ||\r
421 (ShellCommandLineGetCount(Package) > 4)) {\r
099e8ff5 422 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"parse"); \r
a405b86d 423 ShellStatus = SHELL_INVALID_PARAMETER;\r
424 } else {\r
421fbf99
TS
425 if (StreamingUnicode) {\r
426 FileName = L">i";\r
427 TableName = ShellCommandLineGetRawValue(Package, 1);\r
428 ColumnString = ShellCommandLineGetRawValue(Package, 2);\r
429 } else {\r
430 FileName = ShellCommandLineGetRawValue(Package, 1);\r
431 TableName = ShellCommandLineGetRawValue(Package, 2);\r
432 ColumnString = ShellCommandLineGetRawValue(Package, 3);\r
433 }\r
a405b86d 434 if (ShellCommandLineGetValue(Package, L"-i") == NULL) {\r
435 TableNameInstance = (UINTN)-1;\r
436 } else {\r
437 TableNameInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-i"));\r
438 }\r
439 if (ShellCommandLineGetValue(Package, L"-s") == NULL) {\r
440 ShellCommandInstance = 1;\r
441 } else {\r
442 ShellCommandInstance = ShellStrToUintn(ShellCommandLineGetValue(Package, L"-s"));\r
443 }\r
444\r
421fbf99 445 ShellStatus = PerformParsing(FileName, TableName, ShellStrToUintn(ColumnString), TableNameInstance, ShellCommandInstance, StreamingUnicode);\r
a405b86d 446 }\r
447 }\r
448\r
449 //\r
450 // free the command line package\r
451 //\r
452 ShellCommandLineFreeVarList (Package);\r
453\r
454 return (ShellStatus);\r
455}\r
456\r