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