Running the vulture tool on the UPT/Library folder gave the following report. Remove the unnecessary code. - UPT/Library/CommentGenerating.py:50: unused function 'GenGenericComment' (60% confidence) - UPT/Library/CommentGenerating.py:172: unused function 'GenInfPcdTailComment' (60% confidence) - UPT/Library/CommentGenerating.py:185: unused function 'GenInfProtocolPPITailComment' (60% confidence) - UPT/Library/CommentGenerating.py:203: unused function 'GenInfGuidTailComment' (60% confidence) - UPT/Library/Misc.py:504: unused class 'MergeCommentDict' (60% confidence) - UPT/Library/Misc.py:527: unused function 'GenDummyHelpTextObj' (60% confidence) - UPT/Library/ParserValidate.py:110: unused function 'IsValidInfComponentType' (60% confidence) - UPT/Library/ParserValidate.py:122: unused function 'IsValidToolFamily' (60% confidence) - UPT/Library/ParserValidate.py:134: unused function 'IsValidToolTagName' (60% confidence) - UPT/Library/ParserValidate.py:465: unused function 'IsValidBuildNumber' (60% confidence) - UPT/Library/ParserValidate.py:478: unused function 'IsValidDepex' (60% confidence) - UPT/Library/ParserValidate.py:546: unused function 'IsValidVersionString' (60% confidence) - UPT/Library/ParserValidate.py:721: unused function 'CheckUTF16FileHeader' (60% confidence) - UPT/Library/Parsing.py:52: unused function 'GetBuildOption' (60% confidence) - UPT/Library/Parsing.py💯 unused function 'GetLibraryClassOfInf' (60% confidence) - UPT/Library/Parsing.py:150: unused function 'GetPcd' (60% confidence) - UPT/Library/Parsing.py:177: unused function 'GetFeatureFlagPcd' (60% confidence) - UPT/Library/Parsing.py:201: unused function 'GetDynamicDefaultPcd' (60% confidence) - UPT/Library/Parsing.py:227: unused function 'GetDynamicHiiPcd' (60% confidence) - UPT/Library/Parsing.py:254: unused function 'GetDynamicVpdPcd' (60% confidence) - UPT/Library/Parsing.py:277: unused function 'GetComponent' (60% confidence) - UPT/Library/Parsing.py:392: unused function 'GetExec' (60% confidence) - UPT/Library/Parsing.py:416: unused function 'GetComponents' (60% confidence) - UPT/Library/Parsing.py:532: unused function 'GetSource' (60% confidence) - UPT/Library/Parsing.py:581: unused function 'GetGuidsProtocolsPpisOfInf' (60% confidence) - UPT/Library/Parsing.py:595: unused function 'GetGuidsProtocolsPpisOfDec' (60% confidence) - UPT/Library/Parsing.py:645: unused function 'GetPcdOfInf' (60% confidence) - UPT/Library/Parsing.py:682: unused function 'GetPcdOfDec' (60% confidence) - UPT/Library/Parsing.py:739: unused function 'InsertSectionItems' (60% confidence) - UPT/Library/Parsing.py:776: unused function 'GenMetaDatSectionItem' (60% confidence) - UPT/Library/StringUtils.py:87: unused function 'GetLibraryClassesWithModuleType' (60% confidence) - UPT/Library/StringUtils.py:107: unused function 'GetDynamics' (60% confidence) - UPT/Library/StringUtils.py:350: unused function 'GetMultipleValuesOfKeyFromLines' (60% confidence) - UPT/Library/StringUtils.py:396: unused function 'GetSingleValueOfKeyFromLines' (60% confidence) - UPT/Library/StringUtils.py:463: unused function 'PreCheck' (60% confidence) - UPT/Library/StringUtils.py:675: unused function 'StringArrayLength' (60% confidence) - UPT/Library/StringUtils.py:718: unused function 'IsHexDigit' (60% confidence) - UPT/Library/UniClassObject.py:86: unused function 'UniToStr' (60% confidence) - UPT/Library/UniClassObject.py:227: unused attribute 'StringNameByteList' (60% confidence) - UPT/Library/UniClassObject.py:237: unused attribute 'StringNameByteList' (60% confidence) - UPT/Library/UniClassObject.py:377: unused method 'GetIncludeFile' (60% confidence) - UPT/Library/UniClassObject.py:947: unused method 'FindStringValue' (60% confidence) - UPT/Library/UniClassObject.py:957: unused method 'FindByToken' (60% confidence) - UPT/Library/UniClassObject.py:1022: unused method 'ReadIncludeUNIfile' (60% confidence) - UPT/Library/StringUtils.py:718: unused function 'IsHexDigit' (60% confidence) - UPT/Library/Xml/XmlRoutines.py:176: unused function 'XmlElementList' (60% confidence) - UPT/Library/Xml/XmlRoutines.py:202: unused function 'XmlNodeName' (60% confidence) Signed-off-by: Pierre Gondois <pierre.gondois@arm.com>
391 lines
14 KiB
Python
391 lines
14 KiB
Python
## @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 = {}
|
|
|
|
## 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)
|
|
|
|
## 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 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], '')
|
|
|
|
## 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])
|
|
|
|
## 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)
|
|
|
|
## 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
|