1## @file 2# This file contained the parser for sections in INF file 3# 4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> 5# 6# SPDX-License-Identifier: BSD-2-Clause-Patent 7# 8 9''' 10InfSectionParser 11''' 12## 13# Import Modules 14# 15from copy import deepcopy 16import re 17 18from Library.StringUtils import GetSplitValueList 19from Library.CommentParsing import ParseHeaderCommentSection 20from Library.CommentParsing import ParseComment 21 22from Library import DataType as DT 23 24import Logger.Log as Logger 25from Logger import StringTable as ST 26from Logger.ToolError import FORMAT_INVALID 27 28from Object.Parser.InfDefineObject import InfDefObject 29from Object.Parser.InfBuildOptionObject import InfBuildOptionsObject 30from Object.Parser.InfLibraryClassesObject import InfLibraryClassObject 31from Object.Parser.InfPackagesObject import InfPackageObject 32from Object.Parser.InfPcdObject import InfPcdObject 33from Object.Parser.InfSoucesObject import InfSourcesObject 34from Object.Parser.InfUserExtensionObject import InfUserExtensionObject 35from Object.Parser.InfProtocolObject import InfProtocolObject 36from Object.Parser.InfPpiObject import InfPpiObject 37from Object.Parser.InfGuidObject import InfGuidObject 38from Object.Parser.InfDepexObject import InfDepexObject 39from Object.Parser.InfBinaryObject import InfBinariesObject 40from Object.Parser.InfHeaderObject import InfHeaderObject 41from Object.Parser.InfMisc import InfSpecialCommentObject 42from Object.Parser.InfMisc import InfHobObject 43from Object.Parser.InfMisc import InfBootModeObject 44from Object.Parser.InfMisc import InfEventObject 45from Parser.InfParserMisc import gINF_SECTION_DEF 46from Parser.InfDefineSectionParser import InfDefinSectionParser 47from Parser.InfBuildOptionSectionParser import InfBuildOptionSectionParser 48from Parser.InfSourceSectionParser import InfSourceSectionParser 49from Parser.InfLibrarySectionParser import InfLibrarySectionParser 50from Parser.InfPackageSectionParser import InfPackageSectionParser 51from Parser.InfGuidPpiProtocolSectionParser import InfGuidPpiProtocolSectionParser 52from Parser.InfBinarySectionParser import InfBinarySectionParser 53from Parser.InfPcdSectionParser import InfPcdSectionParser 54from Parser.InfDepexSectionParser import InfDepexSectionParser 55 56## GetSpecialStr2 57# 58# GetSpecialStr2 59# 60def GetSpecialStr2(ItemList, FileName, LineNo, SectionString): 61 Str2 = '' 62 # 63 # S2 may be Platform or ModuleType 64 # 65 if len(ItemList) == 3: 66 # 67 # Except [LibraryClass], [Depex] 68 # section can has more than 2 items in section header string, 69 # others should report error. 70 # 71 if not (ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() or \ 72 ItemList[0].upper() == DT.TAB_DEPEX.upper() or \ 73 ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper()): 74 if ItemList[2] != '': 75 Logger.Error('Parser', 76 FORMAT_INVALID, 77 ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID % (SectionString), 78 File=FileName, 79 Line=LineNo, 80 ExtraData=SectionString) 81 Str2 = ItemList[2] 82 elif len(ItemList) == 4: 83 # 84 # Except [UserExtension] 85 # section can has 4 items in section header string, 86 # others should report error. 87 # 88 if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper() or ItemList[0].upper() == DT.TAB_DEPEX.upper(): 89 if ItemList[3] != '': 90 Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \ 91 % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) 92 93 if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): 94 Str2 = ItemList[2] + ' | ' + ItemList[3] 95 else: 96 Str2 = ItemList[2] 97 98 elif len(ItemList) > 4: 99 Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \ 100 % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) 101 102 return Str2 103 104## ProcessUseExtHeader 105# 106# 107def ProcessUseExtHeader(ItemList): 108 NewItemList = [] 109 AppendContent = '' 110 CompleteFlag = False 111 for Item in ItemList: 112 if Item.startswith('\"') and not Item.endswith('\"'): 113 AppendContent = Item 114 CompleteFlag = True 115 elif Item.endswith('\"') and not Item.startswith('\"'): 116 # 117 # Should not have an userId or IdString not starts with " before but ends with ". 118 # 119 if not CompleteFlag: 120 return False, [] 121 AppendContent = AppendContent + "." + Item 122 NewItemList.append(AppendContent) 123 CompleteFlag = False 124 AppendContent = '' 125 elif Item.endswith('\"') and Item.startswith('\"'): 126 # 127 # Common item, not need to combine the information 128 # 129 NewItemList.append(Item) 130 else: 131 if not CompleteFlag: 132 NewItemList.append(Item) 133 else: 134 AppendContent = AppendContent + "." + Item 135 136 if len(NewItemList) > 4: 137 return False, [] 138 139 return True, NewItemList 140 141## GetArch 142# 143# GetArch 144# 145def GetArch(ItemList, ArchList, FileName, LineNo, SectionString): 146 # 147 # S1 is always Arch 148 # 149 if len(ItemList) > 1: 150 Arch = ItemList[1] 151 else: 152 Arch = 'COMMON' 153 ArchList.add(Arch) 154 155 # 156 # 'COMMON' must not be used with specific ARCHs at the same section 157 # 158 if 'COMMON' in ArchList and len(ArchList) > 1: 159 Logger.Error('Parser', 160 FORMAT_INVALID, 161 ST.ERR_INF_PARSER_SECTION_ARCH_CONFLICT, 162 File=FileName, 163 Line=LineNo, 164 ExtraData=SectionString) 165 166 return Arch, ArchList 167 168## InfSectionParser 169# 170# Inherit from object 171# 172class InfSectionParser(InfDefinSectionParser, 173 InfBuildOptionSectionParser, 174 InfSourceSectionParser, 175 InfLibrarySectionParser, 176 InfPackageSectionParser, 177 InfGuidPpiProtocolSectionParser, 178 InfBinarySectionParser, 179 InfPcdSectionParser, 180 InfDepexSectionParser): 181 # 182 # Parser objects used to implement singleton 183 # 184 MetaFiles = {} 185 186 ## Factory method 187 # 188 # One file, one parser object. This factory method makes sure that there's 189 # only one object constructed for one meta file. 190 # 191 # @param Class class object of real AutoGen class 192 # (InfParser, DecParser or DscParser) 193 # @param FilePath The path of meta file 194 # 195 def __new__(cls, FilePath, *args, **kwargs): 196 if args: 197 pass 198 if kwargs: 199 pass 200 if FilePath in cls.MetaFiles: 201 return cls.MetaFiles[FilePath] 202 else: 203 ParserObject = super(InfSectionParser, cls).__new__(cls) 204 cls.MetaFiles[FilePath] = ParserObject 205 return ParserObject 206 207 def __init__(self): 208 InfDefinSectionParser.__init__(self) 209 InfBuildOptionSectionParser.__init__(self) 210 InfSourceSectionParser.__init__(self) 211 InfLibrarySectionParser.__init__(self) 212 InfPackageSectionParser.__init__(self) 213 InfGuidPpiProtocolSectionParser.__init__(self) 214 InfBinarySectionParser.__init__(self) 215 InfPcdSectionParser.__init__(self) 216 InfDepexSectionParser.__init__(self) 217 # 218 # Initialize all objects that an INF file will generated. 219 # 220 self.InfDefSection = InfDefObject() 221 self.InfBuildOptionSection = InfBuildOptionsObject() 222 self.InfLibraryClassSection = InfLibraryClassObject() 223 self.InfPackageSection = InfPackageObject() 224 self.InfPcdSection = InfPcdObject(list(self.MetaFiles.keys())[0]) 225 self.InfSourcesSection = InfSourcesObject() 226 self.InfUserExtensionSection = InfUserExtensionObject() 227 self.InfProtocolSection = InfProtocolObject() 228 self.InfPpiSection = InfPpiObject() 229 self.InfGuidSection = InfGuidObject() 230 self.InfDepexSection = InfDepexObject() 231 self.InfPeiDepexSection = InfDepexObject() 232 self.InfDxeDepexSection = InfDepexObject() 233 self.InfSmmDepexSection = InfDepexObject() 234 self.InfBinariesSection = InfBinariesObject() 235 self.InfHeader = InfHeaderObject() 236 self.InfBinaryHeader = InfHeaderObject() 237 self.InfSpecialCommentSection = InfSpecialCommentObject() 238 239 # 240 # A List for store define section content. 241 # 242 self._PcdNameList = [] 243 self._SectionName = '' 244 self._SectionType = 0 245 self.RelaPath = '' 246 self.FileName = '' 247 248 # 249 # File Header content parser 250 # 251 def InfHeaderParser(self, Content, InfHeaderObject2, FileName, IsBinaryHeader = False): 252 if IsBinaryHeader: 253 (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName, True) 254 if not Abstract or not Description or not Copyright or not License: 255 Logger.Error('Parser', 256 FORMAT_INVALID, 257 ST.ERR_INVALID_BINARYHEADER_FORMAT, 258 File=FileName) 259 else: 260 (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName) 261 # 262 # Not process file name now, for later usage. 263 # 264 if self.FileName: 265 pass 266 267 # 268 # Insert Abstract, Description, CopyRight, License into header object 269 # 270 InfHeaderObject2.SetAbstract(Abstract) 271 InfHeaderObject2.SetDescription(Description) 272 InfHeaderObject2.SetCopyright(Copyright) 273 InfHeaderObject2.SetLicense(License) 274 275 276 277 278 ## Section header parser 279 # 280 # The section header is always in following format: 281 # 282 # [section_name.arch<.platform|module_type>] 283 # 284 # @param String A string contained the content need to be parsed. 285 # 286 def SectionHeaderParser(self, SectionString, FileName, LineNo): 287 _Scope = [] 288 _SectionName = '' 289 ArchList = set() 290 _ValueList = [] 291 _PcdNameList = [DT.TAB_INF_FIXED_PCD.upper(), 292 DT.TAB_INF_FEATURE_PCD.upper(), 293 DT.TAB_INF_PATCH_PCD.upper(), 294 DT.TAB_INF_PCD.upper(), 295 DT.TAB_INF_PCD_EX.upper() 296 ] 297 SectionString = SectionString.strip() 298 for Item in GetSplitValueList(SectionString[1:-1], DT.TAB_COMMA_SPLIT): 299 if Item == '': 300 Logger.Error('Parser', 301 FORMAT_INVALID, 302 ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""), 303 File=FileName, 304 Line=LineNo, 305 ExtraData=SectionString) 306 ItemList = GetSplitValueList(Item, DT.TAB_SPLIT) 307 # 308 # different section should not mix in one section 309 # Allow different PCD type sections mixed together 310 # 311 if _SectionName.upper() not in _PcdNameList: 312 if _SectionName != '' and _SectionName.upper() != ItemList[0].upper(): 313 Logger.Error('Parser', 314 FORMAT_INVALID, 315 ST.ERR_INF_PARSER_SECTION_NAME_DUPLICATE, 316 File=FileName, 317 Line=LineNo, 318 ExtraData=SectionString) 319 elif _PcdNameList[1] in [_SectionName.upper(), ItemList[0].upper()] and \ 320 (_SectionName.upper()!= ItemList[0].upper()): 321 Logger.Error('Parser', 322 FORMAT_INVALID, 323 ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""), 324 File=FileName, 325 Line=LineNo, 326 ExtraData=SectionString) 327 328 _SectionName = ItemList[0] 329 if _SectionName.upper() in gINF_SECTION_DEF: 330 self._SectionType = gINF_SECTION_DEF[_SectionName.upper()] 331 else: 332 self._SectionType = DT.MODEL_UNKNOWN 333 Logger.Error("Parser", 334 FORMAT_INVALID, 335 ST.ERR_INF_PARSER_UNKNOWN_SECTION, 336 File=FileName, 337 Line=LineNo, 338 ExtraData=SectionString) 339 340 # 341 # Get Arch 342 # 343 Str1, ArchList = GetArch(ItemList, ArchList, FileName, LineNo, SectionString) 344 345 # 346 # For [Defines] section, do special check. 347 # 348 if ItemList[0].upper() == DT.TAB_COMMON_DEFINES.upper(): 349 if len(ItemList) != 1: 350 Logger.Error('Parser', 351 FORMAT_INVALID, 352 ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString), 353 File=FileName, Line=LineNo, ExtraData=SectionString) 354 355 # 356 # For [UserExtension] section, do special check. 357 # 358 if ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): 359 360 RetValue = ProcessUseExtHeader(ItemList) 361 362 if not RetValue[0]: 363 Logger.Error('Parser', 364 FORMAT_INVALID, 365 ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString), 366 File=FileName, Line=LineNo, ExtraData=SectionString) 367 else: 368 ItemList = RetValue[1] 369 370 if len(ItemList) == 3: 371 ItemList.append('COMMON') 372 373 Str1 = ItemList[1] 374 375 # 376 # For Library classes, need to check module type. 377 # 378 if ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() and len(ItemList) == 3: 379 if ItemList[2] != '': 380 ModuleTypeList = GetSplitValueList(ItemList[2], DT.TAB_VALUE_SPLIT) 381 for Item in ModuleTypeList: 382 if Item.strip() not in DT.MODULE_LIST: 383 Logger.Error('Parser', 384 FORMAT_INVALID, 385 ST.ERR_INF_PARSER_DEFINE_MODULETYPE_INVALID % (Item), 386 File=FileName, 387 Line=LineNo, 388 ExtraData=SectionString) 389 # 390 # GetSpecialStr2 391 # 392 Str2 = GetSpecialStr2(ItemList, FileName, LineNo, SectionString) 393 394 _Scope.append([Str1, Str2]) 395 396 _NewValueList = [] 397 _AppendFlag = True 398 if _SectionName.upper() in _PcdNameList: 399 for ValueItem in _ValueList: 400 if _SectionName.upper() == ValueItem[0].upper() and Str1.upper() not in ValueItem[1].split(): 401 ValueItem[1] = ValueItem[1] + " " + Str1 402 _AppendFlag = False 403 elif _SectionName.upper() == ValueItem[0].upper() and Str1.upper() in ValueItem[1].split(): 404 _AppendFlag = False 405 406 _NewValueList.append(ValueItem) 407 408 _ValueList = _NewValueList 409 410 if _AppendFlag: 411 if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): 412 _ValueList.append([_SectionName, Str1, Str2, LineNo]) 413 else: 414 if len(ItemList) == 4: 415 _ValueList.append([_SectionName, Str1, Str2, ItemList[3], LineNo]) 416 417 self.SectionHeaderContent = deepcopy(_ValueList) 418 419 ## GenSpecialSectionList 420 # 421 # @param SpecialSectionList: a list of list, of which item's format 422 # (Comment, LineNum) 423 # @param ContainerFile: Input value for filename of Inf file 424 # 425 def InfSpecialCommentParser (self, SpecialSectionList, InfSectionObject, ContainerFile, SectionType): 426 ReFindSpecialCommentRe = re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL) 427 ReFindHobArchRe = re.compile(r"""[Hh][Oo][Bb]\.([^,]*)""", re.DOTALL) 428 if self.FileName: 429 pass 430 SpecialObjectList = [] 431 ArchList = [] 432 if SectionType == DT.TYPE_EVENT_SECTION: 433 TokenDict = DT.EVENT_TOKENS 434 elif SectionType == DT.TYPE_HOB_SECTION: 435 TokenDict = DT.HOB_TOKENS 436 else: 437 TokenDict = DT.BOOTMODE_TOKENS 438 439 for List in SpecialSectionList: 440 # 441 # Hob has Arch attribute, need to be handled specially here 442 # 443 if SectionType == DT.TYPE_HOB_SECTION: 444 445 MatchObject = ReFindSpecialCommentRe.search(List[0][0]) 446 HobSectionStr = MatchObject.group(1) 447 ArchList = [] 448 for Match in ReFindHobArchRe.finditer(HobSectionStr): 449 Arch = Match.groups(1)[0].upper() 450 ArchList.append(Arch) 451 CommentSoFar = '' 452 for Index in range(1, len(List)): 453 Result = ParseComment(List[Index], DT.ALL_USAGE_TOKENS, TokenDict, [], False) 454 Usage = Result[0] 455 Type = Result[1] 456 HelpText = Result[3] 457 458 if Usage == DT.ITEM_UNDEFINED and Type == DT.ITEM_UNDEFINED: 459 if HelpText is None: 460 HelpText = '' 461 if not HelpText.endswith('\n'): 462 HelpText += '\n' 463 CommentSoFar += HelpText 464 else: 465 if HelpText: 466 CommentSoFar += HelpText 467 if SectionType == DT.TYPE_EVENT_SECTION: 468 SpecialObject = InfEventObject() 469 SpecialObject.SetEventType(Type) 470 SpecialObject.SetUsage(Usage) 471 SpecialObject.SetHelpString(CommentSoFar) 472 elif SectionType == DT.TYPE_HOB_SECTION: 473 SpecialObject = InfHobObject() 474 SpecialObject.SetHobType(Type) 475 SpecialObject.SetUsage(Usage) 476 SpecialObject.SetHelpString(CommentSoFar) 477 if len(ArchList) >= 1: 478 SpecialObject.SetSupArchList(ArchList) 479 else: 480 SpecialObject = InfBootModeObject() 481 SpecialObject.SetSupportedBootModes(Type) 482 SpecialObject.SetUsage(Usage) 483 SpecialObject.SetHelpString(CommentSoFar) 484 485 SpecialObjectList.append(SpecialObject) 486 CommentSoFar = '' 487 if not InfSectionObject.SetSpecialComments(SpecialObjectList, 488 SectionType): 489 Logger.Error('InfParser', 490 FORMAT_INVALID, 491 ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (SectionType), 492 ContainerFile 493 ) 494