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