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