## @file | |
# This file contained the parser for sections in INF file | |
# | |
# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR> | |
# | |
# 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 | |
) |