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={}, SelfReplacement=False): 247 NewList = [] 248 for String in StringList: 249 if isinstance(String, type('')): 250 NewList.append(ReplaceMacro(String, MacroDefinitions, SelfReplacement)) 251 else: 252 NewList.append(String) 253 254 return NewList 255 256## Replace macro in string 257# 258# This method replace macros used in given string. The macros are given in a 259# dictionary. 260# 261# @param String String to be processed 262# @param MacroDefinitions The macro definitions in the form of dictionary 263# @param SelfReplacement To decide whether replace un-defined macro to '' 264# 265# @retval string The string whose macros are replaced 266# 267def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement=False, RaiseError=False): 268 LastString = String 269 while String and MacroDefinitions: 270 MacroUsed = GlobalData.gMacroRefPattern.findall(String) 271 # no macro found in String, stop replacing 272 if len(MacroUsed) == 0: 273 break 274 275 for Macro in MacroUsed: 276 if Macro not in MacroDefinitions: 277 if RaiseError: 278 raise SymbolNotFound("%s not defined" % Macro) 279 if SelfReplacement: 280 String = String.replace("$(%s)" % Macro, '') 281 continue 282 if "$(%s)" % Macro not in MacroDefinitions[Macro]: 283 String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro]) 284 # in case there's macro not defined 285 if String == LastString: 286 break 287 LastString = String 288 289 return String 290 291## NormPath 292# 293# Create a normal path 294# And replace DEFINE in the path 295# 296# @param Path: The input value for Path to be converted 297# @param Defines: A set for DEFINE statement 298# 299# @retval Path Formatted path 300# 301def NormPath(Path, Defines={}): 302 IsRelativePath = False 303 if Path: 304 if Path[0] == '.': 305 IsRelativePath = True 306 # 307 # Replace with Define 308 # 309 if Defines: 310 Path = ReplaceMacro(Path, Defines) 311 # 312 # To local path format 313 # 314 Path = os.path.normpath(Path) 315 if Path.startswith(GlobalData.gWorkspace) and not Path.startswith(GlobalData.gBuildDirectory) and not os.path.exists(Path): 316 Path = Path[len (GlobalData.gWorkspace):] 317 if Path[0] == os.path.sep: 318 Path = Path[1:] 319 Path = mws.join(GlobalData.gWorkspace, Path) 320 321 if IsRelativePath and Path[0] != '.': 322 Path = os.path.join('.', Path) 323 324 return Path 325 326## CleanString 327# 328# Remove comments in a string 329# Remove spaces 330# 331# @param Line: The string to be cleaned 332# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT 333# 334# @retval Path Formatted path 335# 336def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False): 337 # 338 # remove whitespace 339 # 340 Line = Line.strip(); 341 # 342 # Replace Edk's comment character 343 # 344 if AllowCppStyleComment: 345 Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) 346 # 347 # remove comments, but we should escape comment character in string 348 # 349 InDoubleQuoteString = False 350 InSingleQuoteString = False 351 CommentInString = False 352 for Index in range(0, len(Line)): 353 if Line[Index] == '"' and not InSingleQuoteString: 354 InDoubleQuoteString = not InDoubleQuoteString 355 elif Line[Index] == "'" and not InDoubleQuoteString: 356 InSingleQuoteString = not InSingleQuoteString 357 elif Line[Index] == CommentCharacter and (InSingleQuoteString or InDoubleQuoteString): 358 CommentInString = True 359 elif Line[Index] == CommentCharacter and not (InSingleQuoteString or InDoubleQuoteString): 360 Line = Line[0: Index] 361 break 362 363 if CommentInString and BuildOption: 364 Line = Line.replace('"', '') 365 ChIndex = Line.find('#') 366 while ChIndex >= 0: 367 if GlobalData.gIsWindows: 368 if ChIndex == 0 or Line[ChIndex - 1] != '^': 369 Line = Line[0:ChIndex] + '^' + Line[ChIndex:] 370 ChIndex = Line.find('#', ChIndex + 2) 371 else: 372 ChIndex = Line.find('#', ChIndex + 1) 373 else: 374 if ChIndex == 0 or Line[ChIndex - 1] != '\\': 375 Line = Line[0:ChIndex] + '\\' + Line[ChIndex:] 376 ChIndex = Line.find('#', ChIndex + 2) 377 else: 378 ChIndex = Line.find('#', ChIndex + 1) 379 # 380 # remove whitespace again 381 # 382 Line = Line.strip(); 383 384 return Line 385 386## CleanString2 387# 388# Split statement with comments in a string 389# Remove spaces 390# 391# @param Line: The string to be cleaned 392# @param CommentCharacter: Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT 393# 394# @retval Path Formatted path 395# 396def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): 397 # 398 # remove whitespace 399 # 400 Line = Line.strip(); 401 # 402 # Replace Edk's comment character 403 # 404 if AllowCppStyleComment: 405 Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) 406 # 407 # separate comments and statements, but we should escape comment character in string 408 # 409 InDoubleQuoteString = False 410 InSingleQuoteString = False 411 CommentInString = False 412 Comment = '' 413 for Index in range(0, len(Line)): 414 if Line[Index] == '"' and not InSingleQuoteString: 415 InDoubleQuoteString = not InDoubleQuoteString 416 elif Line[Index] == "'" and not InDoubleQuoteString: 417 InSingleQuoteString = not InSingleQuoteString 418 elif Line[Index] == CommentCharacter and (InDoubleQuoteString or InSingleQuoteString): 419 CommentInString = True 420 elif Line[Index] == CommentCharacter and not (InDoubleQuoteString or InSingleQuoteString): 421 Comment = Line[Index:].strip() 422 Line = Line[0:Index].strip() 423 break 424 425 return Line, Comment 426 427## GetMultipleValuesOfKeyFromLines 428# 429# Parse multiple strings to clean comment and spaces 430# The result is saved to KeyValues 431# 432# @param Lines: The content to be parsed 433# @param Key: Reserved 434# @param KeyValues: To store data after parsing 435# @param CommentCharacter: Comment char, used to ignore comment content 436# 437# @retval True Successfully executed 438# 439def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter): 440 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] 441 LineList = Lines.split('\n') 442 for Line in LineList: 443 Line = CleanString(Line, CommentCharacter) 444 if Line != '' and Line[0] != CommentCharacter: 445 KeyValues.append(Line) 446 447 return True 448 449## GetDefineValue 450# 451# Parse a DEFINE statement to get defined value 452# DEFINE Key Value 453# 454# @param String: The content to be parsed 455# @param Key: The key of DEFINE statement 456# @param CommentCharacter: Comment char, used to ignore comment content 457# 458# @retval string The defined value 459# 460def GetDefineValue(String, Key, CommentCharacter): 461 String = CleanString(String) 462 return String[String.find(Key + ' ') + len(Key + ' ') : ] 463 464## GetHexVerValue 465# 466# Get a Hex Version Value 467# 468# @param VerString: The version string to be parsed 469# 470# 471# @retval: If VerString is incorrectly formatted, return "None" which will break the build. 472# If VerString is correctly formatted, return a Hex value of the Version Number (0xmmmmnnnn) 473# where mmmm is the major number and nnnn is the adjusted minor number. 474# 475def GetHexVerValue(VerString): 476 VerString = CleanString(VerString) 477 478 if gHumanReadableVerPatt.match(VerString): 479 ValueList = VerString.split('.') 480 Major = ValueList[0] 481 Minor = ValueList[1] 482 if len(Minor) == 1: 483 Minor += '0' 484 DeciValue = (int(Major) << 16) + int(Minor); 485 return "0x%08x" % DeciValue 486 elif gHexVerPatt.match(VerString): 487 return VerString 488 else: 489 return None 490 491 492## GetSingleValueOfKeyFromLines 493# 494# Parse multiple strings as below to get value of each definition line 495# Key1 = Value1 496# Key2 = Value2 497# The result is saved to Dictionary 498# 499# @param Lines: The content to be parsed 500# @param Dictionary: To store data after parsing 501# @param CommentCharacter: Comment char, be used to ignore comment content 502# @param KeySplitCharacter: Key split char, between key name and key value. Key1 = Value1, '=' is the key split char 503# @param ValueSplitFlag: Value split flag, be used to decide if has multiple values 504# @param ValueSplitCharacter: Value split char, be used to split multiple values. Key1 = Value1|Value2, '|' is the value split char 505# 506# @retval True Successfully executed 507# 508def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter): 509 Lines = Lines.split('\n') 510 Keys = [] 511 Value = '' 512 DefineValues = [''] 513 SpecValues = [''] 514 515 for Line in Lines: 516 # 517 # Handle DEFINE and SPEC 518 # 519 if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1: 520 if '' in DefineValues: 521 DefineValues.remove('') 522 DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter)) 523 continue 524 if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1: 525 if '' in SpecValues: 526 SpecValues.remove('') 527 SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter)) 528 continue 529 530 # 531 # Handle Others 532 # 533 LineList = Line.split(KeySplitCharacter, 1) 534 if len(LineList) >= 2: 535 Key = LineList[0].split() 536 if len(Key) == 1 and Key[0][0] != CommentCharacter: 537 # 538 # Remove comments and white spaces 539 # 540 LineList[1] = CleanString(LineList[1], CommentCharacter) 541 if ValueSplitFlag: 542 Value = list(map(string.strip, LineList[1].split(ValueSplitCharacter))) 543 else: 544 Value = CleanString(LineList[1], CommentCharacter).splitlines() 545 546 if Key[0] in Dictionary: 547 if Key[0] not in Keys: 548 Dictionary[Key[0]] = Value 549 Keys.append(Key[0]) 550 else: 551 Dictionary[Key[0]].extend(Value) 552 else: 553 Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0] 554 555 if DefineValues == []: 556 DefineValues = [''] 557 if SpecValues == []: 558 SpecValues = [''] 559 Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues 560 Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues 561 562 return True 563 564## The content to be parsed 565# 566# Do pre-check for a file before it is parsed 567# Check $() 568# Check [] 569# 570# @param FileName: Used for error report 571# @param FileContent: File content to be parsed 572# @param SupSectionTag: Used for error report 573# 574def PreCheck(FileName, FileContent, SupSectionTag): 575 LineNo = 0 576 IsFailed = False 577 NewFileContent = '' 578 for Line in FileContent.splitlines(): 579 LineNo = LineNo + 1 580 # 581 # Clean current line 582 # 583 Line = CleanString(Line) 584 585 # 586 # Remove commented line 587 # 588 if Line.find(DataType.TAB_COMMA_SPLIT) == 0: 589 Line = '' 590 # 591 # Check $() 592 # 593 if Line.find('$') > -1: 594 if Line.find('$(') < 0 or Line.find(')') < 0: 595 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) 596 597 # 598 # Check [] 599 # 600 if Line.find('[') > -1 or Line.find(']') > -1: 601 # 602 # Only get one '[' or one ']' 603 # 604 if not (Line.find('[') > -1 and Line.find(']') > -1): 605 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) 606 607 # 608 # Regenerate FileContent 609 # 610 NewFileContent = NewFileContent + Line + '\r\n' 611 612 if IsFailed: 613 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) 614 615 return NewFileContent 616 617## CheckFileType 618# 619# Check if the Filename is including ExtName 620# Return True if it exists 621# Raise a error message if it not exists 622# 623# @param CheckFilename: Name of the file to be checked 624# @param ExtName: Ext name of the file to be checked 625# @param ContainerFilename: The container file which describes the file to be checked, used for error report 626# @param SectionName: Used for error report 627# @param Line: The line in container file which defines the file to be checked 628# 629# @retval True The file type is correct 630# 631def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1): 632 if CheckFilename != '' and CheckFilename is not None: 633 (Root, Ext) = os.path.splitext(CheckFilename) 634 if Ext.upper() != ExtName.upper(): 635 ContainerFile = open(ContainerFilename, 'r').read() 636 if LineNo == -1: 637 LineNo = GetLineNo(ContainerFile, Line) 638 ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName) 639 EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, 640 File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError) 641 642 return True 643 644## CheckFileExist 645# 646# Check if the file exists 647# Return True if it exists 648# Raise a error message if it not exists 649# 650# @param CheckFilename: Name of the file to be checked 651# @param WorkspaceDir: Current workspace dir 652# @param ContainerFilename: The container file which describes the file to be checked, used for error report 653# @param SectionName: Used for error report 654# @param Line: The line in container file which defines the file to be checked 655# 656# @retval The file full path if the file exists 657# 658def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1): 659 CheckFile = '' 660 if CheckFilename != '' and CheckFilename is not None: 661 CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename) 662 if not os.path.isfile(CheckFile): 663 ContainerFile = open(ContainerFilename, 'r').read() 664 if LineNo == -1: 665 LineNo = GetLineNo(ContainerFile, Line) 666 ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName) 667 EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, 668 File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError) 669 670 return CheckFile 671 672## GetLineNo 673# 674# Find the index of a line in a file 675# 676# @param FileContent: Search scope 677# @param Line: Search key 678# 679# @retval int Index of the line 680# @retval -1 The line is not found 681# 682def GetLineNo(FileContent, Line, IsIgnoreComment=True): 683 LineList = FileContent.splitlines() 684 for Index in range(len(LineList)): 685 if LineList[Index].find(Line) > -1: 686 # 687 # Ignore statement in comment 688 # 689 if IsIgnoreComment: 690 if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT: 691 continue 692 return Index + 1 693 694 return -1 695 696## RaiseParserError 697# 698# Raise a parser error 699# 700# @param Line: String which has error 701# @param Section: Used for error report 702# @param File: File which has the string 703# @param Format: Correct format 704# 705def RaiseParserError(Line, Section, File, Format='', LineNo= -1): 706 if LineNo == -1: 707 LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line) 708 ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section) 709 if Format != '': 710 Format = "Correct format is " + Format 711 EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError) 712 713## WorkspaceFile 714# 715# Return a full path with workspace dir 716# 717# @param WorkspaceDir: Workspace dir 718# @param Filename: Relative file name 719# 720# @retval string A full path 721# 722def WorkspaceFile(WorkspaceDir, Filename): 723 return mws.join(NormPath(WorkspaceDir), NormPath(Filename)) 724 725## Split string 726# 727# Remove '"' which startswith and endswith string 728# 729# @param String: The string need to be split 730# 731# @retval String: The string after removed '""' 732# 733def SplitString(String): 734 if String.startswith('\"'): 735 String = String[1:] 736 if String.endswith('\"'): 737 String = String[:-1] 738 739 return String 740 741## Convert To Sql String 742# 743# 1. Replace "'" with "''" in each item of StringList 744# 745# @param StringList: A list for strings to be converted 746# 747def ConvertToSqlString(StringList): 748 return list(map(lambda s: s.replace("'", "''"), StringList)) 749 750## Convert To Sql String 751# 752# 1. Replace "'" with "''" in the String 753# 754# @param String: A String to be converted 755# 756def ConvertToSqlString2(String): 757 return String.replace("'", "''") 758 759# 760# Remove comment block 761# 762def RemoveBlockComment(Lines): 763 IsFindBlockComment = False 764 IsFindBlockCode = False 765 ReservedLine = '' 766 NewLines = [] 767 768 for Line in Lines: 769 Line = Line.strip() 770 # 771 # Remove comment block 772 # 773 if Line.find(DataType.TAB_COMMENT_EDK_START) > -1: 774 ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0] 775 IsFindBlockComment = True 776 if Line.find(DataType.TAB_COMMENT_EDK_END) > -1: 777 Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1] 778 ReservedLine = '' 779 IsFindBlockComment = False 780 if IsFindBlockComment: 781 NewLines.append('') 782 continue 783 784 NewLines.append(Line) 785 return NewLines 786 787# 788# Get String of a List 789# 790def GetStringOfList(List, Split=' '): 791 if not isinstance(List, type([])): 792 return List 793 Str = '' 794 for Item in List: 795 Str = Str + Item + Split 796 797 return Str.strip() 798 799# 800# Get HelpTextList from HelpTextClassList 801# 802def GetHelpTextList(HelpTextClassList): 803 List = [] 804 if HelpTextClassList: 805 for HelpText in HelpTextClassList: 806 if HelpText.String.endswith('\n'): 807 HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')] 808 List.extend(HelpText.String.split('\n')) 809 810 return List 811 812def StringToArray(String): 813 if String.startswith('L"'): 814 if String == "L\"\"": 815 return "{0x00,0x00}" 816 else: 817 return "{%s,0x00,0x00}" % ",".join("0x%02x,0x00" % ord(C) for C in String[2:-1]) 818 elif String.startswith('"'): 819 if String == "\"\"": 820 return "{0x00,0x00}" 821 else: 822 StringLen = len(String[1:-1]) 823 if StringLen % 2: 824 return "{%s,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1]) 825 else: 826 return "{%s,0x00,0x00}" % ",".join("0x%02x" % ord(C) for C in String[1:-1]) 827 elif String.startswith('{'): 828 return "{%s}" % ",".join(C.strip() for C in String[1:-1].split(',')) 829 else: 830 if len(String.split()) % 2: 831 return '{%s,0}' % ','.join(String.split()) 832 else: 833 return '{%s,0,0}' % ','.join(String.split()) 834 835def StringArrayLength(String): 836 if String.startswith('L"'): 837 return (len(String) - 3 + 1) * 2 838 elif String.startswith('"'): 839 return (len(String) - 2 + 1) 840 else: 841 return len(String.split()) + 1 842 843def RemoveDupOption(OptionString, Which="/I", Against=None): 844 OptionList = OptionString.split() 845 ValueList = [] 846 if Against: 847 ValueList += Against 848 for Index in range(len(OptionList)): 849 Opt = OptionList[Index] 850 if not Opt.startswith(Which): 851 continue 852 if len(Opt) > len(Which): 853 Val = Opt[len(Which):] 854 else: 855 Val = "" 856 if Val in ValueList: 857 OptionList[Index] = "" 858 else: 859 ValueList.append(Val) 860 return " ".join(OptionList) 861 862## 863# 864# This acts like the main() function for the script, unless it is 'import'ed into another 865# script. 866# 867if __name__ == '__main__': 868 pass 869 870