## @file | |
# This file is used to define common parsing related functions used in parsing | |
# INF/DEC/DSC process | |
# | |
# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> | |
# | |
# SPDX-License-Identifier: BSD-2-Clause-Patent | |
# | |
''' | |
Parsing | |
''' | |
from __future__ import absolute_import | |
## | |
# Import Modules | |
# | |
import os.path | |
import re | |
from Library.StringUtils import RaiseParserError | |
from Library.StringUtils import GetSplitValueList | |
from Library.StringUtils import CheckFileType | |
from Library.StringUtils import CheckFileExist | |
from Library.StringUtils import CleanString | |
from Library.StringUtils import NormPath | |
from Logger.ToolError import FILE_NOT_FOUND | |
from Logger.ToolError import FatalError | |
from Logger.ToolError import FORMAT_INVALID | |
from Library import DataType | |
from Library.Misc import GuidStructureStringToGuidString | |
from Library.Misc import CheckGuidRegFormat | |
from Logger import StringTable as ST | |
import Logger.Log as Logger | |
from Parser.DecParser import Dec | |
from . import GlobalData | |
gPKG_INFO_DICT = {} | |
## GetBuildOption | |
# | |
# Parse a string with format "[<Family>:]<ToolFlag>=Flag" | |
# Return (Family, ToolFlag, Flag) | |
# | |
# @param String: String with BuildOption statement | |
# @param File: The file which defines build option, used in error report | |
# | |
def GetBuildOption(String, File, LineNo= -1): | |
(Family, ToolChain, Flag) = ('', '', '') | |
if String.find(DataType.TAB_EQUAL_SPLIT) < 0: | |
RaiseParserError(String, 'BuildOptions', File, \ | |
'[<Family>:]<ToolFlag>=Flag', LineNo) | |
else: | |
List = GetSplitValueList(String, DataType.TAB_EQUAL_SPLIT, MaxSplit=1) | |
if List[0].find(':') > -1: | |
Family = List[0][ : List[0].find(':')].strip() | |
ToolChain = List[0][List[0].find(':') + 1 : ].strip() | |
else: | |
ToolChain = List[0].strip() | |
Flag = List[1].strip() | |
return (Family, ToolChain, Flag) | |
## Get Library Class | |
# | |
# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance> | |
# | |
# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance> | |
# @param ContainerFile: The file which describes the library class, used for | |
# error report | |
# | |
def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo= -1): | |
List = GetSplitValueList(Item[0]) | |
SupMod = DataType.SUP_MODULE_LIST_STRING | |
if len(List) != 2: | |
RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, \ | |
'<LibraryClassKeyWord>|<LibraryInstance>') | |
else: | |
CheckFileType(List[1], '.Inf', ContainerFile, \ | |
'library class instance', Item[0], LineNo) | |
CheckFileExist(WorkspaceDir, List[1], ContainerFile, \ | |
'LibraryClasses', Item[0], LineNo) | |
if Item[1] != '': | |
SupMod = Item[1] | |
return (List[0], List[1], SupMod) | |
## Get Library Class | |
# | |
# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>] | |
# [|<TokenSpaceGuidCName>.<PcdCName>] | |
# | |
# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance> | |
# @param ContainerFile: The file which describes the library class, used for | |
# error report | |
# | |
def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo= -1): | |
ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2)) | |
SupMod = DataType.SUP_MODULE_LIST_STRING | |
if len(ItemList) > 5: | |
RaiseParserError\ | |
(Item[0], 'LibraryClasses', ContainerFile, \ | |
'<LibraryClassKeyWord>[|<LibraryInstance>]\ | |
[|<TokenSpaceGuidCName>.<PcdCName>]') | |
else: | |
CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', \ | |
Item[0], LineNo) | |
CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, \ | |
'LibraryClasses', Item[0], LineNo) | |
if ItemList[2] != '': | |
CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', \ | |
ContainerFile, LineNo) | |
if Item[1] != '': | |
SupMod = Item[1] | |
return (ItemList[0], ItemList[1], ItemList[2], SupMod) | |
## CheckPcdTokenInfo | |
# | |
# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName> | |
# | |
# @param TokenInfoString: String to be checked | |
# @param Section: Used for error report | |
# @param File: Used for error report | |
# | |
def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo= -1): | |
Format = '<TokenSpaceGuidCName>.<PcdCName>' | |
if TokenInfoString != '' and TokenInfoString is not None: | |
TokenInfoList = GetSplitValueList(TokenInfoString, DataType.TAB_SPLIT) | |
if len(TokenInfoList) == 2: | |
return True | |
RaiseParserError(TokenInfoString, Section, File, Format, LineNo) | |
## Get Pcd | |
# | |
# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value> | |
# [|<Type>|<MaximumDatumSize>] | |
# | |
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>| | |
# <Value>[|<Type>|<MaximumDatumSize>] | |
# @param ContainerFile: The file which describes the pcd, used for error | |
# report | |
# | |
def GetPcd(Item, Type, ContainerFile, LineNo= -1): | |
TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', '' | |
List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2) | |
if len(List) < 4 or len(List) > 6: | |
RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ | |
'<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\ | |
[|<Type>|<MaximumDatumSize>]', LineNo) | |
else: | |
Value = List[1] | |
MaximumDatumSize = List[2] | |
Token = List[3] | |
if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): | |
(TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type) | |
## Get FeatureFlagPcd | |
# | |
# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE | |
# | |
# @param Item: String as <PcdTokenSpaceGuidCName> | |
# .<TokenCName>|TRUE/FALSE | |
# @param ContainerFile: The file which describes the pcd, used for error | |
# report | |
# | |
def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo= -1): | |
TokenGuid, TokenName, Value = '', '', '' | |
List = GetSplitValueList(Item) | |
if len(List) != 2: | |
RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ | |
'<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', \ | |
LineNo) | |
else: | |
Value = List[1] | |
if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): | |
(TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
return (TokenName, TokenGuid, Value, Type) | |
## Get DynamicDefaultPcd | |
# | |
# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName> | |
# |<Value>[|<DatumTyp>[|<MaxDatumSize>]] | |
# | |
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>| | |
# TRUE/FALSE | |
# @param ContainerFile: The file which describes the pcd, used for error | |
# report | |
# | |
def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo= -1): | |
TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', '' | |
List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2) | |
if len(List) < 4 or len(List) > 8: | |
RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ | |
'<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\ | |
[|<DatumTyp>[|<MaxDatumSize>]]', LineNo) | |
else: | |
Value = List[1] | |
DatumTyp = List[2] | |
MaxDatumSize = List[3] | |
if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): | |
(TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type) | |
## Get DynamicHiiPcd | |
# | |
# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>| | |
# <VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]] | |
# | |
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>| | |
# TRUE/FALSE | |
# @param ContainerFile: The file which describes the pcd, used for error | |
# report | |
# | |
def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo= -1): | |
TokenGuid, TokenName, List1, List2, List3, List4, List5 = \ | |
'', '', '', '', '', '', '' | |
List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2) | |
if len(List) < 6 or len(List) > 8: | |
RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ | |
'<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|\ | |
<VariableGuidCName>|<VariableOffset>[|<DefaultValue>\ | |
[|<MaximumDatumSize>]]', LineNo) | |
else: | |
List1, List2, List3, List4, List5 = \ | |
List[1], List[2], List[3], List[4], List[5] | |
if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): | |
(TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
return (TokenName, TokenGuid, List1, List2, List3, List4, List5, Type) | |
## Get DynamicVpdPcd | |
# | |
# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>| | |
# <VpdOffset>[|<MaximumDatumSize>] | |
# | |
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName> | |
# |TRUE/FALSE | |
# @param ContainerFile: The file which describes the pcd, used for error | |
# report | |
# | |
def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo= -1): | |
TokenGuid, TokenName, List1, List2 = '', '', '', '' | |
List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT) | |
if len(List) < 3 or len(List) > 4: | |
RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \ | |
'<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>\ | |
[|<MaximumDatumSize>]', LineNo) | |
else: | |
List1, List2 = List[1], List[2] | |
if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo): | |
(TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
return (TokenName, TokenGuid, List1, List2, Type) | |
## GetComponent | |
# | |
# Parse block of the components defined in dsc file | |
# Set KeyValues as [ ['component name', [lib1, lib2, lib3], | |
# [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...] | |
# | |
# @param Lines: The content to be parsed | |
# @param KeyValues: To store data after parsing | |
# | |
def GetComponent(Lines, KeyValues): | |
(FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \ | |
FindPcdsDynamicEx) = (False, False, False, False, False, False, False, \ | |
False) | |
ListItem = None | |
LibraryClassItem = [] | |
BuildOption = [] | |
Pcd = [] | |
for Line in Lines: | |
Line = Line[0] | |
# | |
# Ignore !include statement | |
# | |
if Line.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1 or \ | |
Line.upper().find(DataType.TAB_DEFINE + ' ') > -1: | |
continue | |
if FindBlock == False: | |
ListItem = Line | |
# | |
# find '{' at line tail | |
# | |
if Line.endswith('{'): | |
FindBlock = True | |
ListItem = CleanString(Line.rsplit('{', 1)[0], \ | |
DataType.TAB_COMMENT_SPLIT) | |
# | |
# Parse a block content | |
# | |
if FindBlock: | |
if Line.find('<LibraryClasses>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(True, False, False, False, False, False, False) | |
continue | |
if Line.find('<BuildOptions>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, True, False, False, False, False, False) | |
continue | |
if Line.find('<PcdsFeatureFlag>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, True, False, False, False, False) | |
continue | |
if Line.find('<PcdsPatchableInModule>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, True, False, False, False) | |
continue | |
if Line.find('<PcdsFixedAtBuild>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, True, False, False) | |
continue | |
if Line.find('<PcdsDynamic>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, True, False) | |
continue | |
if Line.find('<PcdsDynamicEx>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, False, True) | |
continue | |
if Line.endswith('}'): | |
# | |
# find '}' at line tail | |
# | |
KeyValues.append([ListItem, LibraryClassItem, \ | |
BuildOption, Pcd]) | |
(FindBlock, FindLibraryClass, FindBuildOption, \ | |
FindPcdsFeatureFlag, FindPcdsPatchableInModule, \ | |
FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, False, False, False) | |
LibraryClassItem, BuildOption, Pcd = [], [], [] | |
continue | |
if FindBlock: | |
if FindLibraryClass: | |
LibraryClassItem.append(Line) | |
elif FindBuildOption: | |
BuildOption.append(Line) | |
elif FindPcdsFeatureFlag: | |
Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line)) | |
elif FindPcdsPatchableInModule: | |
Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line)) | |
elif FindPcdsFixedAtBuild: | |
Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line)) | |
elif FindPcdsDynamic: | |
Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line)) | |
elif FindPcdsDynamicEx: | |
Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line)) | |
else: | |
KeyValues.append([ListItem, [], [], []]) | |
return True | |
## GetExec | |
# | |
# Parse a string with format "InfFilename [EXEC = ExecFilename]" | |
# Return (InfFilename, ExecFilename) | |
# | |
# @param String: String with EXEC statement | |
# | |
def GetExec(String): | |
InfFilename = '' | |
ExecFilename = '' | |
if String.find('EXEC') > -1: | |
InfFilename = String[ : String.find('EXEC')].strip() | |
ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip() | |
else: | |
InfFilename = String.strip() | |
return (InfFilename, ExecFilename) | |
## GetComponents | |
# | |
# Parse block of the components defined in dsc file | |
# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], | |
# [pcd1, pcd2, pcd3]], ...] | |
# | |
# @param Lines: The content to be parsed | |
# @param Key: Reserved | |
# @param KeyValues: To store data after parsing | |
# @param CommentCharacter: Comment char, used to ignore comment content | |
# | |
# @retval True Get component successfully | |
# | |
def GetComponents(Lines, KeyValues, CommentCharacter): | |
if Lines.find(DataType.TAB_SECTION_END) > -1: | |
Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1] | |
(FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \ | |
FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, False, False, False) | |
ListItem = None | |
LibraryClassItem = [] | |
BuildOption = [] | |
Pcd = [] | |
LineList = Lines.split('\n') | |
for Line in LineList: | |
Line = CleanString(Line, CommentCharacter) | |
if Line is None or Line == '': | |
continue | |
if FindBlock == False: | |
ListItem = Line | |
# | |
# find '{' at line tail | |
# | |
if Line.endswith('{'): | |
FindBlock = True | |
ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter) | |
# | |
# Parse a block content | |
# | |
if FindBlock: | |
if Line.find('<LibraryClasses>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(True, False, False, False, False, False, False) | |
continue | |
if Line.find('<BuildOptions>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, True, False, False, False, False, False) | |
continue | |
if Line.find('<PcdsFeatureFlag>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, True, False, False, False, False) | |
continue | |
if Line.find('<PcdsPatchableInModule>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, True, False, False, False) | |
continue | |
if Line.find('<PcdsFixedAtBuild>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, True, False, False) | |
continue | |
if Line.find('<PcdsDynamic>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, True, False) | |
continue | |
if Line.find('<PcdsDynamicEx>') != -1: | |
(FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \ | |
FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \ | |
FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, False, True) | |
continue | |
if Line.endswith('}'): | |
# | |
# find '}' at line tail | |
# | |
KeyValues.append([ListItem, LibraryClassItem, BuildOption, \ | |
Pcd]) | |
(FindBlock, FindLibraryClass, FindBuildOption, \ | |
FindPcdsFeatureFlag, FindPcdsPatchableInModule, \ | |
FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \ | |
(False, False, False, False, False, False, False, False) | |
LibraryClassItem, BuildOption, Pcd = [], [], [] | |
continue | |
if FindBlock: | |
if FindLibraryClass: | |
LibraryClassItem.append(Line) | |
elif FindBuildOption: | |
BuildOption.append(Line) | |
elif FindPcdsFeatureFlag: | |
Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line)) | |
elif FindPcdsPatchableInModule: | |
Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line)) | |
elif FindPcdsFixedAtBuild: | |
Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line)) | |
elif FindPcdsDynamic: | |
Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line)) | |
elif FindPcdsDynamicEx: | |
Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line)) | |
else: | |
KeyValues.append([ListItem, [], [], []]) | |
return True | |
## Get Source | |
# | |
# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode> | |
# [|<PcdFeatureFlag>]]]] | |
# | |
# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode> | |
# [|<PcdFeatureFlag>]]]] | |
# @param ContainerFile: The file which describes the library class, used | |
# for error report | |
# | |
def GetSource(Item, ContainerFile, FileRelativePath, LineNo= -1): | |
ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4 | |
List = GetSplitValueList(ItemNew) | |
if len(List) < 5 or len(List) > 9: | |
RaiseParserError(Item, 'Sources', ContainerFile, \ | |
'<Filename>[|<Family>[|<TagName>[|<ToolCode>\ | |
[|<PcdFeatureFlag>]]]]', LineNo) | |
List[0] = NormPath(List[0]) | |
CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', \ | |
Item, LineNo) | |
if List[4] != '': | |
CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo) | |
return (List[0], List[1], List[2], List[3], List[4]) | |
## Get Binary | |
# | |
# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode> | |
# [|<PcdFeatureFlag>]]]] | |
# | |
# @param Item: String as <Filename>[|<Family>[|<TagName> | |
# [|<ToolCode>[|<PcdFeatureFlag>]]]] | |
# @param ContainerFile: The file which describes the library class, | |
# used for error report | |
# | |
def GetBinary(Item, ContainerFile, LineNo= -1): | |
ItemNew = Item + DataType.TAB_VALUE_SPLIT | |
List = GetSplitValueList(ItemNew) | |
if len(List) < 3 or len(List) > 5: | |
RaiseParserError(Item, 'Binaries', ContainerFile, \ | |
"<FileType>|<Filename>[|<Target>\ | |
[|<TokenSpaceGuidCName>.<PcdCName>]]", LineNo) | |
if len(List) >= 4: | |
if List[3] != '': | |
CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo) | |
return (List[0], List[1], List[2], List[3]) | |
elif len(List) == 3: | |
return (List[0], List[1], List[2], '') | |
## Get Guids/Protocols/Ppis | |
# | |
# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>] | |
# | |
# @param Item: String as <GuidCName>[|<PcdFeatureFlag>] | |
# @param Type: Type of parsing string | |
# @param ContainerFile: The file which describes the library class, | |
# used for error report | |
# | |
def GetGuidsProtocolsPpisOfInf(Item): | |
ItemNew = Item + DataType.TAB_VALUE_SPLIT | |
List = GetSplitValueList(ItemNew) | |
return (List[0], List[1]) | |
## Get Guids/Protocols/Ppis | |
# | |
# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue> | |
# | |
# @param Item: String as <GuidCName>=<GuidValue> | |
# @param Type: Type of parsing string | |
# @param ContainerFile: The file which describes the library class, | |
# used for error report | |
# | |
def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo= -1): | |
List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT) | |
if len(List) != 2: | |
RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', \ | |
LineNo) | |
# | |
#convert C-Format Guid to Register Format | |
# | |
if List[1][0] == '{' and List[1][-1] == '}': | |
RegisterFormatGuid = GuidStructureStringToGuidString(List[1]) | |
if RegisterFormatGuid == '': | |
RaiseParserError(Item, Type, ContainerFile, \ | |
'CFormat or RegisterFormat', LineNo) | |
else: | |
if CheckGuidRegFormat(List[1]): | |
RegisterFormatGuid = List[1] | |
else: | |
RaiseParserError(Item, Type, ContainerFile, \ | |
'CFormat or RegisterFormat', LineNo) | |
return (List[0], RegisterFormatGuid) | |
## GetPackage | |
# | |
# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>] | |
# | |
# @param Item: String as <PackagePath>[|<PcdFeatureFlag>] | |
# @param Type: Type of parsing string | |
# @param ContainerFile: The file which describes the library class, | |
# used for error report | |
# | |
def GetPackage(Item, ContainerFile, FileRelativePath, LineNo= -1): | |
ItemNew = Item + DataType.TAB_VALUE_SPLIT | |
List = GetSplitValueList(ItemNew) | |
CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo) | |
CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', \ | |
List[0], LineNo) | |
if List[1] != '': | |
CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo) | |
return (List[0], List[1]) | |
## Get Pcd Values of Inf | |
# | |
# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>] | |
# | |
# @param Item: The string describes pcd | |
# @param Type: The type of Pcd | |
# @param File: The file which describes the pcd, used for error report | |
# | |
def GetPcdOfInf(Item, Type, File, LineNo): | |
Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]' | |
TokenGuid, TokenName, Value, InfType = '', '', '', '' | |
if Type == DataType.TAB_PCDS_FIXED_AT_BUILD: | |
InfType = DataType.TAB_INF_FIXED_PCD | |
elif Type == DataType.TAB_PCDS_PATCHABLE_IN_MODULE: | |
InfType = DataType.TAB_INF_PATCH_PCD | |
elif Type == DataType.TAB_PCDS_FEATURE_FLAG: | |
InfType = DataType.TAB_INF_FEATURE_PCD | |
elif Type == DataType.TAB_PCDS_DYNAMIC_EX: | |
InfType = DataType.TAB_INF_PCD_EX | |
elif Type == DataType.TAB_PCDS_DYNAMIC: | |
InfType = DataType.TAB_INF_PCD | |
List = GetSplitValueList(Item, DataType.TAB_VALUE_SPLIT, 1) | |
TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
if len(TokenInfo) != 2: | |
RaiseParserError(Item, InfType, File, Format, LineNo) | |
else: | |
TokenGuid = TokenInfo[0] | |
TokenName = TokenInfo[1] | |
if len(List) > 1: | |
Value = List[1] | |
else: | |
Value = None | |
return (TokenGuid, TokenName, Value, InfType) | |
## Get Pcd Values of Dec | |
# | |
# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token> | |
# @param Item: Pcd item | |
# @param Type: Pcd type | |
# @param File: Dec file | |
# @param LineNo: Line number | |
# | |
def GetPcdOfDec(Item, Type, File, LineNo= -1): | |
Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>' | |
TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', '' | |
List = GetSplitValueList(Item) | |
if len(List) != 4: | |
RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo) | |
else: | |
Value = List[1] | |
DatumType = List[2] | |
Token = List[3] | |
TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT) | |
if len(TokenInfo) != 2: | |
RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo) | |
else: | |
TokenGuid = TokenInfo[0] | |
TokenName = TokenInfo[1] | |
return (TokenGuid, TokenName, Value, DatumType, Token, Type) | |
## Parse DEFINE statement | |
# | |
# Get DEFINE macros | |
# | |
# @param LineValue: A DEFINE line value | |
# @param StartLine: A DEFINE start line | |
# @param Table: A table | |
# @param FileID: File ID | |
# @param Filename: File name | |
# @param SectionName: DEFINE section name | |
# @param SectionModel: DEFINE section model | |
# @param Arch: DEFINE arch | |
# | |
def ParseDefine(LineValue, StartLine, Table, FileID, SectionName, \ | |
SectionModel, Arch): | |
Logger.Debug(Logger.DEBUG_2, ST.MSG_DEFINE_STATEMENT_FOUND % (LineValue, \ | |
SectionName)) | |
Define = \ | |
GetSplitValueList(CleanString\ | |
(LineValue[LineValue.upper().\ | |
find(DataType.TAB_DEFINE.upper() + ' ') + \ | |
len(DataType.TAB_DEFINE + ' ') : ]), \ | |
DataType.TAB_EQUAL_SPLIT, 1) | |
Table.Insert(DataType.MODEL_META_DATA_DEFINE, Define[0], Define[1], '', \ | |
'', '', Arch, SectionModel, FileID, StartLine, -1, \ | |
StartLine, -1, 0) | |
## InsertSectionItems | |
# | |
# Insert item data of a section to a dict | |
# | |
# @param Model: A model | |
# @param CurrentSection: Current section | |
# @param SectionItemList: Section item list | |
# @param ArchList: Arch list | |
# @param ThirdList: Third list | |
# @param RecordSet: Record set | |
# | |
def InsertSectionItems(Model, SectionItemList, ArchList, \ | |
ThirdList, RecordSet): | |
# | |
# Insert each item data of a section | |
# | |
for Index in range(0, len(ArchList)): | |
Arch = ArchList[Index] | |
Third = ThirdList[Index] | |
if Arch == '': | |
Arch = DataType.TAB_ARCH_COMMON | |
Records = RecordSet[Model] | |
for SectionItem in SectionItemList: | |
LineValue, StartLine, Comment = SectionItem[0], \ | |
SectionItem[1], SectionItem[2] | |
Logger.Debug(4, ST.MSG_PARSING % LineValue) | |
# | |
# And then parse DEFINE statement | |
# | |
if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1: | |
continue | |
# | |
# At last parse other sections | |
# | |
IdNum = -1 | |
Records.append([LineValue, Arch, StartLine, IdNum, Third, Comment]) | |
if RecordSet != {}: | |
RecordSet[Model] = Records | |
## GenMetaDatSectionItem | |
# | |
# @param Key: A key | |
# @param Value: A value | |
# @param List: A list | |
# | |
def GenMetaDatSectionItem(Key, Value, List): | |
if Key not in List: | |
List[Key] = [Value] | |
else: | |
List[Key].append(Value) | |
## GetPkgInfoFromDec | |
# | |
# get package name, guid, version info from dec files | |
# | |
# @param Path: File path | |
# | |
def GetPkgInfoFromDec(Path): | |
PkgName = None | |
PkgGuid = None | |
PkgVersion = None | |
Path = Path.replace('\\', '/') | |
if not os.path.exists(Path): | |
Logger.Error("\nUPT", FILE_NOT_FOUND, File=Path) | |
if Path in gPKG_INFO_DICT: | |
return gPKG_INFO_DICT[Path] | |
try: | |
DecParser = None | |
if Path not in GlobalData.gPackageDict: | |
DecParser = Dec(Path) | |
GlobalData.gPackageDict[Path] = DecParser | |
else: | |
DecParser = GlobalData.gPackageDict[Path] | |
PkgName = DecParser.GetPackageName() | |
PkgGuid = DecParser.GetPackageGuid() | |
PkgVersion = DecParser.GetPackageVersion() | |
gPKG_INFO_DICT[Path] = (PkgName, PkgGuid, PkgVersion) | |
return PkgName, PkgGuid, PkgVersion | |
except FatalError: | |
return None, None, None | |
## GetWorkspacePackage | |
# | |
# Get a list of workspace package information. | |
# | |
def GetWorkspacePackage(): | |
DecFileList = [] | |
WorkspaceDir = GlobalData.gWORKSPACE | |
PackageDir = GlobalData.gPACKAGE_PATH | |
for PkgRoot in [WorkspaceDir] + PackageDir: | |
for Root, Dirs, Files in os.walk(PkgRoot): | |
if 'CVS' in Dirs: | |
Dirs.remove('CVS') | |
if '.svn' in Dirs: | |
Dirs.remove('.svn') | |
for Dir in Dirs: | |
if Dir.startswith('.'): | |
Dirs.remove(Dir) | |
for FileSp in Files: | |
if FileSp.startswith('.'): | |
continue | |
Ext = os.path.splitext(FileSp)[1] | |
if Ext.lower() in ['.dec']: | |
DecFileList.append\ | |
(os.path.normpath(os.path.join(Root, FileSp))) | |
# | |
# abstract package guid, version info from DecFile List | |
# | |
PkgList = [] | |
for DecFile in DecFileList: | |
(PkgName, PkgGuid, PkgVersion) = GetPkgInfoFromDec(DecFile) | |
if PkgName and PkgGuid and PkgVersion: | |
PkgList.append((PkgName, PkgGuid, PkgVersion, DecFile)) | |
return PkgList | |
## GetWorkspaceModule | |
# | |
# Get a list of workspace modules. | |
# | |
def GetWorkspaceModule(): | |
InfFileList = [] | |
WorkspaceDir = GlobalData.gWORKSPACE | |
for Root, Dirs, Files in os.walk(WorkspaceDir): | |
if 'CVS' in Dirs: | |
Dirs.remove('CVS') | |
if '.svn' in Dirs: | |
Dirs.remove('.svn') | |
if 'Build' in Dirs: | |
Dirs.remove('Build') | |
for Dir in Dirs: | |
if Dir.startswith('.'): | |
Dirs.remove(Dir) | |
for FileSp in Files: | |
if FileSp.startswith('.'): | |
continue | |
Ext = os.path.splitext(FileSp)[1] | |
if Ext.lower() in ['.inf']: | |
InfFileList.append\ | |
(os.path.normpath(os.path.join(Root, FileSp))) | |
return InfFileList | |
## MacroParser used to parse macro definition | |
# | |
# @param Line: The content contain linestring and line number | |
# @param FileName: The meta-file file name | |
# @param SectionType: Section for the Line belong to | |
# @param FileLocalMacros: A list contain Macro defined in [Defines] section. | |
# | |
def MacroParser(Line, FileName, SectionType, FileLocalMacros): | |
MacroDefPattern = re.compile("^(DEFINE)[ \t]+") | |
LineContent = Line[0] | |
LineNo = Line[1] | |
Match = MacroDefPattern.match(LineContent) | |
if not Match: | |
# | |
# Not 'DEFINE/EDK_GLOBAL' statement, call decorated method | |
# | |
return None, None | |
TokenList = GetSplitValueList(LineContent[Match.end(1):], \ | |
DataType.TAB_EQUAL_SPLIT, 1) | |
# | |
# Syntax check | |
# | |
if not TokenList[0]: | |
Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACRONAME_NOGIVEN, | |
ExtraData=LineContent, File=FileName, Line=LineNo) | |
if len(TokenList) < 2: | |
Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACROVALUE_NOGIVEN, | |
ExtraData=LineContent, File=FileName, Line=LineNo) | |
Name, Value = TokenList | |
# | |
# DEFINE defined macros | |
# | |
if SectionType == DataType.MODEL_META_DATA_HEADER: | |
FileLocalMacros[Name] = Value | |
ReIsValidMacroName = re.compile(r"^[A-Z][A-Z0-9_]*$", re.DOTALL) | |
if ReIsValidMacroName.match(Name) is None: | |
Logger.Error('Parser', | |
FORMAT_INVALID, | |
ST.ERR_MACRONAME_INVALID % (Name), | |
ExtraData=LineContent, | |
File=FileName, | |
Line=LineNo) | |
# Validate MACRO Value | |
# | |
# <MacroDefinition> ::= [<Comments>]{0,} | |
# "DEFINE" <MACRO> "=" [{<PATH>} {<VALUE>}] <EOL> | |
# <Value> ::= {<NumVal>} {<Boolean>} {<AsciiString>} {<GUID>} | |
# {<CString>} {<UnicodeString>} {<CArray>} | |
# | |
# The definition of <NumVal>, <PATH>, <Boolean>, <GUID>, <CString>, | |
# <UnicodeString>, <CArray> are subset of <AsciiString>. | |
# | |
ReIsValidMacroValue = re.compile(r"^[\x20-\x7e]*$", re.DOTALL) | |
if ReIsValidMacroValue.match(Value) is None: | |
Logger.Error('Parser', | |
FORMAT_INVALID, | |
ST.ERR_MACROVALUE_INVALID % (Value), | |
ExtraData=LineContent, | |
File=FileName, | |
Line=LineNo) | |
return Name, Value | |
## GenSection | |
# | |
# generate section contents | |
# | |
# @param SectionName: indicate the name of the section, details refer to | |
# INF, DEC specs | |
# @param SectionDict: section statement dict, key is SectionAttrs(arch, | |
# moduletype or platform may exist as needed) list | |
# separated by space, | |
# value is statement | |
# | |
def GenSection(SectionName, SectionDict, SplitArch=True, NeedBlankLine=False): | |
Content = '' | |
for SectionAttrs in SectionDict: | |
StatementList = SectionDict[SectionAttrs] | |
if SectionAttrs and SectionName != 'Defines' and SectionAttrs.strip().upper() != DataType.TAB_ARCH_COMMON: | |
if SplitArch: | |
ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_SPACE_SPLIT) | |
else: | |
if SectionName != 'UserExtensions': | |
ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_COMMENT_SPLIT) | |
else: | |
ArchList = [SectionAttrs] | |
for Index in range(0, len(ArchList)): | |
ArchList[Index] = ConvertArchForInstall(ArchList[Index]) | |
Section = '[' + SectionName + '.' + (', ' + SectionName + '.').join(ArchList) + ']' | |
else: | |
Section = '[' + SectionName + ']' | |
Content += '\n' + Section + '\n' | |
if StatementList is not None: | |
for Statement in StatementList: | |
LineList = Statement.split('\n') | |
NewStatement = "" | |
for Line in LineList: | |
# ignore blank comment | |
if not Line.replace("#", '').strip() and SectionName not in ('Defines', 'Hob', 'Event', 'BootMode'): | |
continue | |
# add two space before non-comments line except the comments in Defines section | |
if Line.strip().startswith('#') and SectionName == 'Defines': | |
NewStatement += "%s\n" % Line | |
continue | |
NewStatement += " %s\n" % Line | |
if NeedBlankLine: | |
Content += NewStatement + '\n' | |
else: | |
Content += NewStatement | |
if NeedBlankLine: | |
Content = Content[:-1] | |
if not Content.replace('\\n', '').strip(): | |
return '' | |
return Content | |
## ConvertArchForInstall | |
# if Arch.upper() is in "IA32", "X64", "IPF", and "EBC", it must be upper case. "common" must be lower case. | |
# Anything else, the case must be preserved | |
# | |
# @param Arch: the arch string that need to be converted, it should be stripped before pass in | |
# @return: the arch string that get converted | |
# | |
def ConvertArchForInstall(Arch): | |
if Arch.upper() in [DataType.TAB_ARCH_IA32, DataType.TAB_ARCH_X64, | |
DataType.TAB_ARCH_IPF, DataType.TAB_ARCH_EBC]: | |
Arch = Arch.upper() | |
elif Arch.upper() == DataType.TAB_ARCH_COMMON: | |
Arch = Arch.lower() | |
return Arch |