1## @file 2# This file is used to define common string related functions used in parsing process 3# 4# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> 5# SPDX-License-Identifier: BSD-2-Clause-Patent 6# 7 8## 9# Import Modules 10# 11from __future__ import absolute_import 12import re 13from . import DataType 14import Common.LongFilePathOs as os 15import string 16from . import EdkLogger as EdkLogger 17 18from . import GlobalData 19from .BuildToolError import * 20from CommonDataClass.Exceptions import * 21from Common.LongFilePathSupport import OpenLongFilePath as open 22from Common.MultipleWorkspace import MultipleWorkspace as mws 23 24gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE) 25gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') 26 27## GetSplitValueList 28# 29# Get a value list from a string with multiple values split with SplitTag 30# The default SplitTag is DataType.TAB_VALUE_SPLIT 31# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] 32# 33# @param String: The input string to be splitted 34# @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT 35# @param MaxSplit: The max number of split values, default is -1 36# 37# @retval list() A list for splitted string 38# 39def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): 40 ValueList = [] 41 Last = 0 42 Escaped = False 43 InSingleQuoteString = False 44 InDoubleQuoteString = False 45 InParenthesis = 0 46 for Index in range(0, len(String)): 47 Char = String[Index] 48 49 if not Escaped: 50 # Found a splitter not in a string, split it 51 if (not InSingleQuoteString or not InDoubleQuoteString) and InParenthesis == 0 and Char == SplitTag: 52 ValueList.append(String[Last:Index].strip()) 53 Last = Index + 1 54 if MaxSplit > 0 and len(ValueList) >= MaxSplit: 55 break 56 57 if Char == '\\' and (InSingleQuoteString or InDoubleQuoteString): 58 Escaped = True 59 elif Char == '"' and not InSingleQuoteString: 60 if not InDoubleQuoteString: 61 InDoubleQuoteString = True 62 else: 63 InDoubleQuoteString = False 64 elif Char == "'" and not InDoubleQuoteString: 65 if not InSingleQuoteString: 66 InSingleQuoteString = True 67 else: 68 InSingleQuoteString = False 69 elif Char == '(': 70 InParenthesis = InParenthesis + 1 71 elif Char == ')': 72 InParenthesis = InParenthesis - 1 73 else: 74 Escaped = False 75 76 if Last < len(String): 77 ValueList.append(String[Last:].strip()) 78 elif Last == len(String): 79 ValueList.append('') 80 81 return ValueList 82 83## GetSplitList 84# 85# Get a value list from a string with multiple values split with SplitString 86# The default SplitTag is DataType.TAB_VALUE_SPLIT 87# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] 88# 89# @param String: The input string to be splitted 90# @param SplitStr: The split key, default is DataType.TAB_VALUE_SPLIT 91# @param MaxSplit: The max number of split values, default is -1 92# 93# @retval list() A list for splitted string 94# 95def GetSplitList(String, SplitStr=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): 96 return list(map(lambda l: l.strip(), String.split(SplitStr, MaxSplit))) 97 98## MergeArches 99# 100# Find a key's all arches in dict, add the new arch to the list 101# If not exist any arch, set the arch directly 102# 103# @param Dict: The input value for Dict 104# @param Key: The input value for Key 105# @param Arch: The Arch to be added or merged 106# 107def MergeArches(Dict, Key, Arch): 108 if Key in Dict: 109 Dict[Key].append(Arch) 110 else: 111 Dict[Key] = Arch.split() 112 113## GenDefines 114# 115# Parse a string with format "DEFINE <VarName> = <PATH>" 116# Generate a map Defines[VarName] = PATH 117# Return False if invalid format 118# 119# @param String: String with DEFINE statement 120# @param Arch: Supported Arch 121# @param Defines: DEFINE statement to be parsed 122# 123# @retval 0 DEFINE statement found, and valid 124# @retval 1 DEFINE statement found, but not valid 125# @retval -1 DEFINE statement not found 126# 127def GenDefines(String, Arch, Defines): 128 if String.find(DataType.TAB_DEFINE + ' ') > -1: 129 List = String.replace(DataType.TAB_DEFINE + ' ', '').split(DataType.TAB_EQUAL_SPLIT) 130 if len(List) == 2: 131 Defines[(CleanString(List[0]), Arch)] = CleanString(List[1]) 132 return 0 133 else: 134 return -1 135 136 return 1 137 138## GenInclude 139# 140# Parse a string with format "!include <Filename>" 141# Return the file path 142# Return False if invalid format or NOT FOUND 143# 144# @param String: String with INCLUDE statement 145# @param IncludeFiles: INCLUDE statement to be parsed 146# @param Arch: Supported Arch 147# 148# @retval True 149# @retval False 150# 151def GenInclude(String, IncludeFiles, Arch): 152 if String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1: 153 IncludeFile = CleanString(String[String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') + len(DataType.TAB_INCLUDE + ' ') : ]) 154 MergeArches(IncludeFiles, IncludeFile, Arch) 155 return True 156 else: 157 return False 158 159## GetLibraryClassesWithModuleType 160# 161# Get Library Class definition when no module type defined 162# 163# @param Lines: The content to be parsed 164# @param Key: Reserved 165# @param KeyValues: To store data after parsing 166# @param CommentCharacter: Comment char, used to ignore comment content 167# 168# @retval True Get library classes successfully 169# 170def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter): 171 newKey = SplitModuleType(Key) 172 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] 173 LineList = Lines.splitlines() 174 for Line in LineList: 175 Line = CleanString(Line, CommentCharacter) 176 if Line != '' and Line[0] != CommentCharacter: 177 KeyValues.append([CleanString(Line, CommentCharacter), newKey[1]]) 178 179 return True 180 181## GetDynamics 182# 183# Get Dynamic Pcds 184# 185# @param Lines: The content to be parsed 186# @param Key: Reserved 187# @param KeyValues: To store data after parsing 188# @param CommentCharacter: Comment char, used to ignore comment content 189# 190# @retval True Get Dynamic Pcds successfully 191# 192def GetDynamics(Lines, Key, KeyValues, CommentCharacter): 193 # 194 # Get SkuId Name List 195 # 196 SkuIdNameList = SplitModuleType(Key) 197 198 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] 199 LineList = Lines.splitlines() 200 for Line in LineList: 201 Line = CleanString(Line, CommentCharacter) 202 if Line != '' and Line[0] != CommentCharacter: 203 KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]]) 204 205 return True 206 207## SplitModuleType 208# 209# Split ModuleType out of section defien to get key 210# [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [ 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ] 211# 212# @param Key: String to be parsed 213# 214# @retval ReturnValue A list for module types 215# 216def SplitModuleType(Key): 217 KeyList = Key.split(DataType.TAB_SPLIT) 218 # 219 # Fill in for arch 220 # 221 KeyList.append('') 222 # 223 # Fill in for moduletype 224 # 225 KeyList.append('') 226 ReturnValue = [] 227 KeyValue = KeyList[0] 228 if KeyList[1] != '': 229 KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1] 230 ReturnValue.append(KeyValue) 231 ReturnValue.append(GetSplitValueList(KeyList[2])) 232 233 return ReturnValue 234 235## Replace macro in strings list 236# 237# This method replace macros used in a given string list. The macros are 238# given in a dictionary. 239# 240# @param StringList StringList to be processed 241# @param MacroDefinitions The macro definitions in the form of dictionary 242# @param SelfReplacement To decide whether replace un-defined macro to '' 243# 244# @retval NewList A new string list whose macros are replaced 245# 246def ReplaceMacros(StringList, MacroDefinitions=None, SelfReplacement=False): 247 NewList = [] 248 if MacroDefinitions is None: 249 MacroDefinitions = {} 250 for String in StringList: 251 if isinstance(String, type('')): 252 NewList.append(ReplaceMacro(String, MacroDefinitions, SelfReplacement)) 253 else: 254 NewList.append(String) 255 256 return NewList 257 258## Replace macro in string 259# 260# This method replace macros used in given string. The macros are given in a 261# dictionary. 262# 263# @param String String to be processed 264# @param MacroDefinitions The macro definitions in the form of dictionary 265# @param SelfReplacement To decide whether replace un-defined macro to '' 266# 267# @retval string The string whose macros are replaced 268# 269def ReplaceMacro(String, MacroDefinitions=None, SelfReplacement=False, RaiseError=False): 270 LastString = String 271 if MacroDefinitions is None: 272 MacroDefinitions = {} 273 while String and MacroDefinitions: 274 MacroUsed = GlobalData.gMacroRefPattern.findall(String) 275 # no macro found in String, stop replacing 276 if len(MacroUsed) == 0: 277 break 278 279 for Macro in MacroUsed: 280 if Macro not in MacroDefinitions: 281 if RaiseError: 282 raise SymbolNotFound("%s not defined" % Macro) 283 if SelfReplacement: 284 String = String.replace("$(%s)" % Macro, '') 285 continue 286 if "$(%s)" % Macro not in MacroDefinitions[Macro]: 287 String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro]) 288 # in case there's macro not defined 289 if String == LastString: 290 break 291 LastString = String 292 293 return String 294 295## NormPath 296# 297# Create a normal path 298# And replace DEFINE in the path 299# 300# @param Path: The input value for Path to be converted 301# @param Defines: A set for DEFINE statement 302# 303# @retval Path Formatted path 304# 305def NormPath(Path, Defines=None): 306 IsRelativePath = False 307 if Path: 308 if Path[0] == '.': 309 IsRelativePath = True 310 # 311 # Replace with Define 312 # 313 if Defines: 314 Path = ReplaceMacro(Path, Defines) 315 # 316 # To local path format 317 # 318 Path = os.path.normpath(Path) 319 if Path.startswith(GlobalData.gWorkspace) and not Path.startswith(GlobalData.gBuildDirectory) and not os.path.exists(Path): 320 Path = Path[len (GlobalData.gWorkspace):] 321 if Path[0] == os.path.sep: 322 Path = Path[1:] 323 Path = mws.join(GlobalData.gWorkspace, Path) 324 325 if IsRelativePath and Path[0] != '.': 326 Path = os.path.join('.', Path) 327 328 return Path 329 330## CleanString 331# 332# Remove comments in a string 333# Remove spaces 334# 335# @param Line: The string to be cleaned 336# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT 337# 338# @retval Path Formatted path 339# 340def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False): 341 # 342 # remove whitespace 343 # 344 Line = Line.strip(); 345 # 346 # Replace Edk's comment character 347 # 348 if AllowCppStyleComment: 349 Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) 350 # 351 # remove comments, but we should escape comment character in string 352 # 353 InDoubleQuoteString = False 354 InSingleQuoteString = False 355 CommentInString = False 356 for Index in range(0, len(Line)): 357 if Line[Index] == '"' and not InSingleQuoteString: 358 InDoubleQuoteString = not InDoubleQuoteString 359 elif Line[Index] == "'" and not InDoubleQuoteString: 360 InSingleQuoteString = not InSingleQuoteString 361 elif Line[Index] == CommentCharacter and (InSingleQuoteString or InDoubleQuoteString): 362 CommentInString = True 363 elif Line[Index] == CommentCharacter and not (InSingleQuoteString or InDoubleQuoteString): 364 Line = Line[0: Index] 365 break 366 367 if CommentInString and BuildOption: 368 Line = Line.replace('"', '') 369 ChIndex = Line.find('#') 370 while ChIndex >= 0: 371 if GlobalData.gIsWindows: 372 if ChIndex == 0 or Line[ChIndex - 1] != '^': 373 Line = Line[0:ChIndex] + '^' + Line[ChIndex:] 374 ChIndex = Line.find('#', ChIndex + 2) 375 else: 376 ChIndex = Line.find('#', ChIndex + 1) 377 else: 378 if ChIndex == 0 or Line[ChIndex - 1] != '\\': 379 Line = Line[0:ChIndex] + '\\' + Line[ChIndex:] 380 ChIndex = Line.find('#', ChIndex + 2) 381 else: 382 ChIndex = Line.find('#', ChIndex + 1) 383 # 384 # remove whitespace again 385 # 386 Line = Line.strip(); 387 388 return Line 389 390## CleanString2 391# 392# Split statement with comments in a string 393# Remove spaces 394# 395# @param Line: The string to be cleaned 396# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT 397# 398# @retval Path Formatted path 399# 400def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): 401 # 402 # remove whitespace 403 # 404 Line = Line.strip(); 405 # 406 # Replace Edk's comment character 407 # 408 if AllowCppStyleComment: 409 Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) 410 # 411 # separate comments and statements, but we should escape comment character in string 412 # 413 InDoubleQuoteString = False 414 InSingleQuoteString = False 415 CommentInString = False 416 Comment = '' 417 for Index in range(0, len(Line)): 418 if Line[Index] == '"' and not InSingleQuoteString: 419 InDoubleQuoteString = not InDoubleQuoteString 420 elif Line[Index] == "'" and not InDoubleQuoteString: 421 InSingleQuoteString = not InSingleQuoteString 422 elif Line[Index] == CommentCharacter and (InDoubleQuoteString or InSingleQuoteString): 423 CommentInString = True 424 elif Line[Index] == CommentCharacter and not (InDoubleQuoteString or InSingleQuoteString): 425 Comment = Line[Index:].strip() 426 Line = Line[0:Index].strip() 427 break 428 429 return Line, Comment 430 431## GetMultipleValuesOfKeyFromLines 432# 433# Parse multiple strings to clean comment and spaces 434# The result is saved to KeyValues 435# 436# @param Lines: The content to be parsed 437# @param Key: Reserved 438# @param KeyValues: To store data after parsing 439# @param CommentCharacter: Comment char, used to ignore comment content 440# 441# @retval True Successfully executed 442# 443def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter): 444 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] 445 LineList = Lines.split('\n') 446 for Line in LineList: 447 Line = CleanString(Line, CommentCharacter) 448 if Line != '' and Line[0] != CommentCharacter: 449 KeyValues.append(Line) 450 451 return True 452 453## GetDefineValue 454# 455# Parse a DEFINE statement to get defined value 456# DEFINE Key Value 457# 458# @param String: The content to be parsed 459# @param Key: The key of DEFINE statement 460# @param CommentCharacter: Comment char, used to ignore comment content 461# 462# @retval string The defined value 463# 464def GetDefineValue(String, Key, CommentCharacter): 465 String = CleanString(String) 466 return String[String.find(Key + ' ') + len(Key + ' ') : ] 467 468## GetHexVerValue 469# 470# Get a Hex Version Value 471# 472# @param VerString: The version string to be parsed 473# 474# 475# @retval: If VerString is incorrectly formatted, return "None" which will break the build. 476# If VerString is correctly formatted, return a Hex value of the Version Number (0xmmmmnnnn) 477# where mmmm is the major number and nnnn is the adjusted minor number. 478# 479def GetHexVerValue(VerString): 480 VerString = CleanString(VerString) 481 482 if gHumanReadableVerPatt.match(VerString): 483 ValueList = VerString.split('.') 484 Major = ValueList[0] 485 Minor = ValueList[1] 486 if len(Minor) == 1: 487 Minor += '0' 488 DeciValue = (int(Major) << 16) + int(Minor); 489 return "0x%08x" % DeciValue 490 elif gHexVerPatt.match(VerString): 491 return VerString 492 else: 493 return None 494 495 496## GetSingleValueOfKeyFromLines 497# 498# Parse multiple strings as below to get value of each definition line 499# Key1 = Value1 500# Key2 = Value2 501# The result is saved to Dictionary 502# 503# @param Lines: The content to be parsed 504# @param Dictionary: To store data after parsing 505# @param CommentCharacter: Comment char, be used to ignore comment content 506# @param KeySplitCharacter: Key split char, between key name and key value. Key1 = Value1, '=' is the key split char 507# @param ValueSplitFlag: Value split flag, be used to decide if has multiple values 508# @param ValueSplitCharacter: Value split char, be used to split multiple values. Key1 = Value1|Value2, '|' is the value split char 509# 510# @retval True Successfully executed 511# 512def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter): 513 Lines = Lines.split('\n') 514 Keys = [] 515 Value = '' 516 DefineValues = [''] 517 SpecValues = [''] 518 519 for Line in Lines: 520 # 521 # Handle DEFINE and SPEC 522 # 523 if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1: 524 if '' in DefineValues: 525 DefineValues.remove('') 526 DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter)) 527 continue 528 if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1: 529 if '' in SpecValues: 530 SpecValues.remove('') 531 SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter)) 532 continue 533 534 # 535 # Handle Others 536 # 537 LineList = Line.split(KeySplitCharacter, 1) 538 if len(LineList) >= 2: 539 Key = LineList[0].split() 540 if len(Key) == 1 and Key[0][0] != CommentCharacter: 541 # 542 # Remove comments and white spaces 543 # 544 LineList[1] = CleanString(LineList[1], CommentCharacter) 545 if ValueSplitFlag: 546 Value = list(map(string.strip, LineList[1].split(ValueSplitCharacter))) 547 else: 548 Value = CleanString(LineList[1], CommentCharacter).splitlines() 549 550 if Key[0] in Dictionary: 551 if Key[0] not in Keys: 552 Dictionary[Key[0]] = Value 553 Keys.append(Key[0]) 554 else: 555 Dictionary[Key[0]].extend(Value) 556 else: 557 Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0] 558 559 if DefineValues == []: 560 DefineValues = [''] 561 if SpecValues == []: 562 SpecValues = [''] 563 Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues 564 Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues 565 566 return True 567 568## The content to be parsed 569# 570# Do pre-check for a file before it is parsed 571# Check $() 572# Check [] 573# 574# @param FileName: Used for error report 575# @param FileContent: File content to be parsed 576# @param SupSectionTag: Used for error report 577# 578def PreCheck(FileName, FileContent, SupSectionTag): 579 LineNo = 0 580 IsFailed = False 581 NewFileContent = '' 582 for Line in FileContent.splitlines(): 583 LineNo = LineNo + 1 584 # 585 # Clean current line 586 # 587 Line = CleanString(Line) 588 589 # 590 # Remove commented line 591 # 592 if Line.find(DataType.TAB_COMMA_SPLIT) == 0: 593 Line = '' 594 # 595 # Check $() 596 # 597 if Line.find('$') > -1: 598 if Line.find('$(') < 0 or Line.find(')') < 0: 599 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) 600 601 # 602 # Check [] 603 # 604 if Line.find('[') > -1 or Line.find(']') > -1: 605 # 606 # Only get one '[' or one ']' 607 # 608 if not (Line.find('[') > -1 and Line.find(']') > -1): 609 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) 610 611 # 612 # Regenerate FileContent 613 # 614 NewFileContent = NewFileContent + Line + '\r\n' 615 616 if IsFailed: 617 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) 618 619 return NewFileContent 620 621## CheckFileType 622# 623# Check if the Filename is including ExtName 624# Return True if it exists 625# Raise a error message if it not exists 626# 627# @param CheckFilename: Name of the file to be checked 628# @param ExtName: Ext name of the file to be checked 629# @param ContainerFilename: The container file which describes the file to be checked, used for error report 630# @param SectionName: Used for error report 631# @param Line: The line in container file which defines the file to be checked 632# 633# @retval True The file type is correct 634# 635def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1): 636 if CheckFilename != '' and CheckFilename is not None: 637 (Root, Ext) = os.path.splitext(CheckFilename) 638 if Ext.upper() != ExtName.upper(): 639 ContainerFile = open(ContainerFilename, 'r').read() 640 if LineNo == -1: 641 LineNo = GetLineNo(ContainerFile, Line) 642 ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName) 643 EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, 644 File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError) 645 646 return True 647 648## CheckFileExist 649# 650# Check if the file exists 651# Return True if it exists 652# Raise a error message if it not exists 653# 654# @param CheckFilename: Name of the file to be checked 655# @param WorkspaceDir: Current workspace dir 656# @param ContainerFilename: The container file which describes the file to be checked, used for error report 657# @param SectionName: Used for error report 658# @param Line: The line in container file which defines the file to be checked 659# 660# @retval The file full path if the file exists 661# 662def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1): 663 CheckFile = '' 664 if CheckFilename != '' and CheckFilename is not None: 665 CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename) 666 if not os.path.isfile(CheckFile): 667 ContainerFile = open(ContainerFilename, 'r').read() 668 if LineNo == -1: 669 LineNo = GetLineNo(ContainerFile, Line) 670 ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName) 671 EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, 672 File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError) 673 674 return CheckFile 675 676## GetLineNo 677# 678# Find the index of a line in a file 679# 680# @param FileContent: Search scope 681# @param Line: Search key 682# 683# @retval int Index of the line 684# @retval -1 The line is not found 685# 686def GetLineNo(FileContent, Line, IsIgnoreComment=True): 687 LineList = FileContent.splitlines() 688 for Index in range(len(LineList)): 689 if LineList[Index].find(Line) > -1: 690 # 691 # Ignore statement in comment 692 # 693 if IsIgnoreComment: 694 if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT: 695 continue 696 return Index + 1 697 698 return -1 699 700## RaiseParserError 701# 702# Raise a parser error 703# 704# @param Line: String which has error 705# @param Section: Used for error report 706# @param File: File which has the string 707# @param Format: Correct format 708# 709def RaiseParserError(Line, Section, File, Format='', LineNo= -1): 710 if LineNo == -1: 711 LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line) 712 ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section) 713 if Format != '': 714 Format = "Correct format is " + Format 715 EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError) 716 717## WorkspaceFile 718# 719# Return a full path with workspace dir 720# 721# @param WorkspaceDir: Workspace dir 722# @param Filename: Relative file name 723# 724# @retval string A full path 725# 726def WorkspaceFile(WorkspaceDir, Filename): 727 return mws.join(NormPath(WorkspaceDir), NormPath(Filename)) 728 729## Split string 730# 731# Remove '"' which startswith and endswith string 732# 733# @param String: The string need to be split 734# 735# @retval String: The string after removed '""' 736# 737def SplitString(String): 738 if String.startswith('\"'): 739 String = String[1:] 740 if String.endswith('\"'): 741 String = String[:-1] 742 743 return String 744 745## Convert To Sql String 746# 747# 1. Replace "'" with "''" in each item of StringList 748# 749# @param StringList: A list for strings to be converted 750# 751def ConvertToSqlString(StringList): 752 return list(map(lambda s: s.replace("'", "''"), StringList)) 753 754## Convert To Sql String 755# 756# 1. Replace "'" with "''" in the String 757# 758# @param String: A String to be converted 759# 760def ConvertToSqlString2(String): 761 return String.replace("'", "''") 762 763# 764# Remove comment block 765# 766def RemoveBlockComment(Lines): 767 IsFindBlockComment = False 768 IsFindBlockCode = False 769 ReservedLine = '' 770 NewLines = [] 771 772 for Line in Lines: 773 Line = Line.strip() 774 # 775 # Remove comment block 776 # 777 if Line.find(DataType.TAB_COMMENT_EDK_START) > -1: 778 ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0] 779 IsFindBlockComment = True 780 if Line.find(DataType.TAB_COMMENT_EDK_END) > -1: 781 Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1] 782 ReservedLine = '' 783 IsFindBlockComment = False 784 if IsFindBlockComment: 785 NewLines.append('') 786 continue 787 788 NewLines.append(Line) 789 return NewLines 790 791# 792# Get String of a List 793# 794def GetStringOfList(List, Split=' '): 795 if not isinstance(List, type([])): 796 return List 797 Str = '' 798 for Item in List: 799 Str = Str + Item + Split 800 801 return Str.strip() 802 803# 804# Get HelpTextList from HelpTextClassList 805# 806def GetHelpTextList(HelpTextClassList): 807 List = [] 808 if HelpTextClassList: 809 for HelpText in HelpTextClassList: 810 if HelpText.String.endswith('\n'): 811 HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')] 812 List.extend(HelpText.String.split('\n')) 813 814 return List 815 816def StringToArray(String): 817 if String.startswith('L"'): 818 if String == "L\"\"": 819 return "{0x00,0x00}" 820 else: 821 return "{%s,0x00,0x00}" % ",".join("0x%02x,0x00" % ord(C) for C in String[2:-1]) 822 elif String.startswith('"'): 823 if String == "\"\"": 824 return "{0x00,0x00}" 825 else: 826 StringLen = len(String[1:-1]) 827 if StringLen % 2: 828 return "{%s,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1]) 829 else: 830 return "{%s,0x00,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1]) 831 elif String.startswith('{'): 832 return "{%s}" % ",".join(C.strip() for C in String[1:-1].split(',')) 833 else: 834 if len(String.split()) % 2: 835 return '{%s,0}' % ','.join(String.split()) 836 else: 837 return '{%s,0,0}' % ','.join(String.split()) 838 839def StringArrayLength(String): 840 if String.startswith('L"'): 841 return (len(String) - 3 + 1) * 2 842 elif String.startswith('"'): 843 return (len(String) - 2 + 1) 844 else: 845 return len(String.split()) + 1 846 847def RemoveDupOption(OptionString, Which="/I", Against=None): 848 OptionList = OptionString.split() 849 ValueList = [] 850 if Against: 851 ValueList += Against 852 for Index in range(len(OptionList)): 853 Opt = OptionList[Index] 854 if not Opt.startswith(Which): 855 continue 856 if len(Opt) > len(Which): 857 Val = Opt[len(Which):] 858 else: 859 Val = "" 860 if Val in ValueList: 861 OptionList[Index] = "" 862 else: 863 ValueList.append(Val) 864 return " ".join(OptionList) 865 866## 867# 868# This acts like the main() function for the script, unless it is 'import'ed into another 869# script. 870# 871if __name__ == '__main__': 872 pass 873 874