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