## @file # This file contained the parser for sections in INF file # # Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
# # This program and the accompanying materials are licensed and made available # under the terms and conditions of the BSD License which accompanies this # distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php # # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. # ''' InfSectionParser ''' ## # Import Modules # from copy import deepcopy import re from Library.String import GetSplitValueList from Library.CommentParsing import ParseHeaderCommentSection from Library.CommentParsing import ParseComment from Library import DataType as DT import Logger.Log as Logger from Logger import StringTable as ST from Logger.ToolError import FORMAT_INVALID from Object.Parser.InfDefineObject import InfDefObject from Object.Parser.InfBuildOptionObject import InfBuildOptionsObject from Object.Parser.InfLibraryClassesObject import InfLibraryClassObject from Object.Parser.InfPackagesObject import InfPackageObject from Object.Parser.InfPcdObject import InfPcdObject from Object.Parser.InfSoucesObject import InfSourcesObject from Object.Parser.InfUserExtensionObject import InfUserExtensionObject from Object.Parser.InfProtocolObject import InfProtocolObject from Object.Parser.InfPpiObject import InfPpiObject from Object.Parser.InfGuidObject import InfGuidObject from Object.Parser.InfDepexObject import InfDepexObject from Object.Parser.InfBinaryObject import InfBinariesObject from Object.Parser.InfHeaderObject import InfHeaderObject from Object.Parser.InfMisc import InfSpecialCommentObject from Object.Parser.InfMisc import InfHobObject from Object.Parser.InfMisc import InfBootModeObject from Object.Parser.InfMisc import InfEventObject from Parser.InfParserMisc import gINF_SECTION_DEF from Parser.InfDefineSectionParser import InfDefinSectionParser from Parser.InfBuildOptionSectionParser import InfBuildOptionSectionParser from Parser.InfSourceSectionParser import InfSourceSectionParser from Parser.InfLibrarySectionParser import InfLibrarySectionParser from Parser.InfPackageSectionParser import InfPackageSectionParser from Parser.InfGuidPpiProtocolSectionParser import InfGuidPpiProtocolSectionParser from Parser.InfBinarySectionParser import InfBinarySectionParser from Parser.InfPcdSectionParser import InfPcdSectionParser from Parser.InfDepexSectionParser import InfDepexSectionParser ## GetSpecialStr2 # # GetSpecialStr2 # def GetSpecialStr2(ItemList, FileName, LineNo, SectionString): Str2 = '' # # S2 may be Platform or ModuleType # if len(ItemList) == 3: # # Except [LibraryClass], [Depex] # section can has more than 2 items in section header string, # others should report error. # if not (ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() or \ ItemList[0].upper() == DT.TAB_DEPEX.upper() or \ ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper()): if ItemList[2] != '': Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) Str2 = ItemList[2] elif len(ItemList) == 4: # # Except [UserExtension] # section can has 4 items in section header string, # others should report error. # if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper() or ItemList[0].upper() == DT.TAB_DEPEX.upper(): if ItemList[3] != '': Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \ % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): Str2 = ItemList[2] + ' | ' + ItemList[3] else: Str2 = ItemList[2] elif len(ItemList) > 4: Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \ % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) return Str2 ## ProcessUseExtHeader # # def ProcessUseExtHeader(ItemList): NewItemList = [] AppendContent = '' CompleteFlag = False for Item in ItemList: if Item.startswith('\"') and not Item.endswith('\"'): AppendContent = Item CompleteFlag = True elif Item.endswith('\"') and not Item.startswith('\"'): # # Should not have an userId or IdString not starts with " before but ends with ". # if not CompleteFlag: return False, [] AppendContent = AppendContent + "." + Item NewItemList.append(AppendContent) CompleteFlag = False AppendContent = '' elif Item.endswith('\"') and Item.startswith('\"'): # # Common item, not need to combine the information # NewItemList.append(Item) else: if not CompleteFlag: NewItemList.append(Item) else: AppendContent = AppendContent + "." + Item if len(NewItemList) > 4: return False, [] return True, NewItemList ## GetArch # # GetArch # def GetArch(ItemList, ArchList, FileName, LineNo, SectionString): # # S1 is always Arch # if len(ItemList) > 1: Arch = ItemList[1] else: Arch = 'COMMON' ArchList.add(Arch) # # 'COMMON' must not be used with specific ARCHs at the same section # if 'COMMON' in ArchList and len(ArchList) > 1: Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SECTION_ARCH_CONFLICT, File=FileName, Line=LineNo, ExtraData=SectionString) return Arch, ArchList ## InfSectionParser # # Inherit from object # class InfSectionParser(InfDefinSectionParser, InfBuildOptionSectionParser, InfSourceSectionParser, InfLibrarySectionParser, InfPackageSectionParser, InfGuidPpiProtocolSectionParser, InfBinarySectionParser, InfPcdSectionParser, InfDepexSectionParser): # # Parser objects used to implement singleton # MetaFiles = {} ## Factory method # # One file, one parser object. This factory method makes sure that there's # only one object constructed for one meta file. # # @param Class class object of real AutoGen class # (InfParser, DecParser or DscParser) # @param FilePath The path of meta file # def __new__(cls, FilePath, *args, **kwargs): if args: pass if kwargs: pass if FilePath in cls.MetaFiles: return cls.MetaFiles[FilePath] else: ParserObject = super(InfSectionParser, cls).__new__(cls) cls.MetaFiles[FilePath] = ParserObject return ParserObject def __init__(self): InfDefinSectionParser.__init__(self) InfBuildOptionSectionParser.__init__(self) InfSourceSectionParser.__init__(self) InfLibrarySectionParser.__init__(self) InfPackageSectionParser.__init__(self) InfGuidPpiProtocolSectionParser.__init__(self) InfBinarySectionParser.__init__(self) InfPcdSectionParser.__init__(self) InfDepexSectionParser.__init__(self) # # Initialize all objects that an INF file will generated. # self.InfDefSection = InfDefObject() self.InfBuildOptionSection = InfBuildOptionsObject() self.InfLibraryClassSection = InfLibraryClassObject() self.InfPackageSection = InfPackageObject() self.InfPcdSection = InfPcdObject(self.MetaFiles.keys()[0]) self.InfSourcesSection = InfSourcesObject() self.InfUserExtensionSection = InfUserExtensionObject() self.InfProtocolSection = InfProtocolObject() self.InfPpiSection = InfPpiObject() self.InfGuidSection = InfGuidObject() self.InfDepexSection = InfDepexObject() self.InfPeiDepexSection = InfDepexObject() self.InfDxeDepexSection = InfDepexObject() self.InfSmmDepexSection = InfDepexObject() self.InfBinariesSection = InfBinariesObject() self.InfHeader = InfHeaderObject() self.InfBinaryHeader = InfHeaderObject() self.InfSpecialCommentSection = InfSpecialCommentObject() # # A List for store define section content. # self._PcdNameList = [] self._SectionName = '' self._SectionType = 0 self.RelaPath = '' self.FileName = '' # # File Header content parser # def InfHeaderParser(self, Content, InfHeaderObject2, FileName, IsBinaryHeader = False): if IsBinaryHeader: (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName, True) if not Abstract or not Description or not Copyright or not License: Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INVALID_BINARYHEADER_FORMAT, File=FileName) else: (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName) # # Not process file name now, for later usage. # if self.FileName: pass # # Insert Abstract, Description, CopyRight, License into header object # InfHeaderObject2.SetAbstract(Abstract) InfHeaderObject2.SetDescription(Description) InfHeaderObject2.SetCopyright(Copyright) InfHeaderObject2.SetLicense(License) ## Section header parser # # The section header is always in following format: # # [section_name.arch<.platform|module_type>] # # @param String A string contained the content need to be parsed. # def SectionHeaderParser(self, SectionString, FileName, LineNo): _Scope = [] _SectionName = '' ArchList = set() _ValueList = [] _PcdNameList = [DT.TAB_INF_FIXED_PCD.upper(), DT.TAB_INF_FEATURE_PCD.upper(), DT.TAB_INF_PATCH_PCD.upper(), DT.TAB_INF_PCD.upper(), DT.TAB_INF_PCD_EX.upper() ] SectionString = SectionString.strip() for Item in GetSplitValueList(SectionString[1:-1], DT.TAB_COMMA_SPLIT): if Item == '': Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""), File=FileName, Line=LineNo, ExtraData=SectionString) ItemList = GetSplitValueList(Item, DT.TAB_SPLIT) # # different section should not mix in one section # Allow different PCD type sections mixed together # if _SectionName.upper() not in _PcdNameList: if _SectionName != '' and _SectionName.upper() != ItemList[0].upper(): Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SECTION_NAME_DUPLICATE, File=FileName, Line=LineNo, ExtraData=SectionString) elif _PcdNameList[1] in [_SectionName.upper(), ItemList[0].upper()] and \ (_SectionName.upper()!= ItemList[0].upper()): Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""), File=FileName, Line=LineNo, ExtraData=SectionString) _SectionName = ItemList[0] if _SectionName.upper() in gINF_SECTION_DEF: self._SectionType = gINF_SECTION_DEF[_SectionName.upper()] else: self._SectionType = DT.MODEL_UNKNOWN Logger.Error("Parser", FORMAT_INVALID, ST.ERR_INF_PARSER_UNKNOWN_SECTION, File=FileName, Line=LineNo, ExtraData=SectionString) # # Get Arch # Str1, ArchList = GetArch(ItemList, ArchList, FileName, LineNo, SectionString) # # For [Defines] section, do special check. # if ItemList[0].upper() == DT.TAB_COMMON_DEFINES.upper(): if len(ItemList) != 1: Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) # # For [UserExtension] section, do special check. # if ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): RetValue = ProcessUseExtHeader(ItemList) if not RetValue[0]: Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString) else: ItemList = RetValue[1] if len(ItemList) == 3: ItemList.append('COMMON') Str1 = ItemList[1] # # For Library classes, need to check module type. # if ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() and len(ItemList) == 3: if ItemList[2] != '': ModuleTypeList = GetSplitValueList(ItemList[2], DT.TAB_VALUE_SPLIT) for Item in ModuleTypeList: if Item.strip() not in DT.MODULE_LIST: Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_DEFINE_MODULETYPE_INVALID % (Item), File=FileName, Line=LineNo, ExtraData=SectionString) # # GetSpecialStr2 # Str2 = GetSpecialStr2(ItemList, FileName, LineNo, SectionString) _Scope.append([Str1, Str2]) _NewValueList = [] _AppendFlag = True if _SectionName.upper() in _PcdNameList: for ValueItem in _ValueList: if _SectionName.upper() == ValueItem[0].upper() and Str1.upper() not in ValueItem[1].split(): ValueItem[1] = ValueItem[1] + " " + Str1 _AppendFlag = False elif _SectionName.upper() == ValueItem[0].upper() and Str1.upper() in ValueItem[1].split(): _AppendFlag = False _NewValueList.append(ValueItem) _ValueList = _NewValueList if _AppendFlag: if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper(): _ValueList.append([_SectionName, Str1, Str2, LineNo]) else: if len(ItemList) == 4: _ValueList.append([_SectionName, Str1, Str2, ItemList[3], LineNo]) self.SectionHeaderContent = deepcopy(_ValueList) ## GenSpecialSectionList # # @param SpecialSectionList: a list of list, of which item's format # (Comment, LineNum) # @param ContainerFile: Input value for filename of Inf file # def InfSpecialCommentParser (self, SpecialSectionList, InfSectionObject, ContainerFile, SectionType): ReFindSpecialCommentRe = re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL) ReFindHobArchRe = re.compile(r"""[Hh][Oo][Bb]\.([^,]*)""", re.DOTALL) if self.FileName: pass SpecialObjectList = [] ArchList = [] if SectionType == DT.TYPE_EVENT_SECTION: TokenDict = DT.EVENT_TOKENS elif SectionType == DT.TYPE_HOB_SECTION: TokenDict = DT.HOB_TOKENS else: TokenDict = DT.BOOTMODE_TOKENS for List in SpecialSectionList: # # Hob has Arch attribute, need to be handled specially here # if SectionType == DT.TYPE_HOB_SECTION: MatchObject = ReFindSpecialCommentRe.search(List[0][0]) HobSectionStr = MatchObject.group(1) ArchList = [] for Match in ReFindHobArchRe.finditer(HobSectionStr): Arch = Match.groups(1)[0].upper() ArchList.append(Arch) CommentSoFar = '' for Index in xrange(1, len(List)): Result = ParseComment(List[Index], DT.ALL_USAGE_TOKENS, TokenDict, [], False) Usage = Result[0] Type = Result[1] HelpText = Result[3] if Usage == DT.ITEM_UNDEFINED and Type == DT.ITEM_UNDEFINED: if HelpText is None: HelpText = '' if not HelpText.endswith('\n'): HelpText += '\n' CommentSoFar += HelpText else: if HelpText: CommentSoFar += HelpText if SectionType == DT.TYPE_EVENT_SECTION: SpecialObject = InfEventObject() SpecialObject.SetEventType(Type) SpecialObject.SetUsage(Usage) SpecialObject.SetHelpString(CommentSoFar) elif SectionType == DT.TYPE_HOB_SECTION: SpecialObject = InfHobObject() SpecialObject.SetHobType(Type) SpecialObject.SetUsage(Usage) SpecialObject.SetHelpString(CommentSoFar) if len(ArchList) >= 1: SpecialObject.SetSupArchList(ArchList) else: SpecialObject = InfBootModeObject() SpecialObject.SetSupportedBootModes(Type) SpecialObject.SetUsage(Usage) SpecialObject.SetHelpString(CommentSoFar) SpecialObjectList.append(SpecialObject) CommentSoFar = '' if not InfSectionObject.SetSpecialComments(SpecialObjectList, SectionType): Logger.Error('InfParser', FORMAT_INVALID, ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (SectionType), ContainerFile )