X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FUPT%2FLibrary%2FMisc.py;h=e16d309ef8838a52bb43ad061f96263976c968dd;hb=64285f15264906c761b5a6772b5b590b32caa03c;hp=b67cd102d1601e89ee6cfbe0d063366ce077d1b4;hpb=2bcc713e74b944bb5aefb433ef33fb4002a62d76;p=mirror_edk2.git diff --git a/BaseTools/Source/Python/UPT/Library/Misc.py b/BaseTools/Source/Python/UPT/Library/Misc.py index b67cd102d1..e16d309ef8 100644 --- a/BaseTools/Source/Python/UPT/Library/Misc.py +++ b/BaseTools/Source/Python/UPT/Library/Misc.py @@ -1,974 +1,1125 @@ -## @file -# Common routines used by all tools -# -# Copyright (c) 2011, 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. -# - -''' -Misc -''' - -## -# Import Modules -# -import os.path -from os import access -from os import F_OK -from os import makedirs -from os import getcwd -from os import chdir -from os import listdir -from os import remove -from os import rmdir -from os import linesep -from os import walk -from os import environ -import re -from UserDict import IterableUserDict - -import Logger.Log as Logger -from Logger import StringTable as ST -from Logger import ToolError -from Library import GlobalData -from Library.DataType import SUP_MODULE_LIST -from Library.DataType import END_OF_LINE -from Library.DataType import TAB_SPLIT -from Library.DataType import LANGUAGE_EN_US -from Library.String import GetSplitValueList -from Library.ParserValidate import IsValidHexVersion -from Library.ParserValidate import IsValidPath -from Object.POM.CommonObject import TextObject - -## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C -# structure style -# -# @param Guid: The GUID string -# -def GuidStringToGuidStructureString(Guid): - GuidList = Guid.split('-') - Result = '{' - for Index in range(0, 3, 1): - Result = Result + '0x' + GuidList[Index] + ', ' - Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] - for Index in range(0, 12, 2): - Result = Result + ', 0x' + GuidList[4][Index:Index + 2] - Result += '}}' - return Result - -## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -# -# @param GuidValue: The GUID value -# -def CheckGuidRegFormat(GuidValue): - ## Regular expression used to find out register format of GUID - # - RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-" - "([0-9a-fA-F]){4}-" - "([0-9a-fA-F]){4}-" - "([0-9a-fA-F]){4}-" - "([0-9a-fA-F]){12}\s*$") - - if RegFormatGuidPattern.match(GuidValue): - return True - else: - return False - - -## Convert GUID string in C structure style to -# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx -# -# @param GuidValue: The GUID value in C structure format -# -def GuidStructureStringToGuidString(GuidValue): - GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\ - replace(" ", "").replace(";", "") - GuidValueList = GuidValueString.split(",") - if len(GuidValueList) != 11: - return '' - try: - return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( - int(GuidValueList[0], 16), - int(GuidValueList[1], 16), - int(GuidValueList[2], 16), - int(GuidValueList[3], 16), - int(GuidValueList[4], 16), - int(GuidValueList[5], 16), - int(GuidValueList[6], 16), - int(GuidValueList[7], 16), - int(GuidValueList[8], 16), - int(GuidValueList[9], 16), - int(GuidValueList[10], 16) - ) - except BaseException: - return '' - -## Create directories -# -# @param Directory: The directory name -# -def CreateDirectory(Directory): - if Directory == None or Directory.strip() == "": - return True - try: - if not access(Directory, F_OK): - makedirs(Directory) - except BaseException: - return False - return True - -## Remove directories, including files and sub-directories in it -# -# @param Directory: The directory name -# -def RemoveDirectory(Directory, Recursively=False): - if Directory == None or Directory.strip() == "" or not \ - os.path.exists(Directory): - return - if Recursively: - CurrentDirectory = getcwd() - chdir(Directory) - for File in listdir("."): - if os.path.isdir(File): - RemoveDirectory(File, Recursively) - else: - remove(File) - chdir(CurrentDirectory) - rmdir(Directory) - -## Store content in file -# -# This method is used to save file only when its content is changed. This is -# quite useful for "make" system to decide what will be re-built and what -# won't. -# -# @param File: The path of file -# @param Content: The new content of the file -# @param IsBinaryFile: The flag indicating if the file is binary file -# or not -# -def SaveFileOnChange(File, Content, IsBinaryFile=True): - if not IsBinaryFile: - Content = Content.replace("\n", linesep) - - if os.path.exists(File): - try: - if Content == open(File, "rb").read(): - return False - except BaseException: - Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) - - CreateDirectory(os.path.dirname(File)) - try: - FileFd = open(File, "wb") - FileFd.write(Content) - FileFd.close() - except BaseException: - Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) - - return True - -## Get all files of a directory -# -# @param Root: Root dir -# @param SkipList : The files need be skipped -# -def GetFiles(Root, SkipList=None, FullPath=True): - OriPath = os.path.normpath(Root) - FileList = [] - for Root, Dirs, Files in walk(Root): - if SkipList: - for Item in SkipList: - if Item in Dirs: - Dirs.remove(Item) - for Dir in Dirs: - if Dir.startswith('.'): - Dirs.remove(Dir) - - for File in Files: - if File.startswith('.'): - continue - File = os.path.normpath(os.path.join(Root, File)) - if not FullPath: - File = File[len(OriPath) + 1:] - FileList.append(File) - - return FileList - -## Get all non-metadata files of a directory -# -# @param Root: Root Dir -# @param SkipList : List of path need be skipped -# @param FullPath: True if the returned file should be full path -# @param PrefixPath: the path that need to be added to the files found -# @return: the list of files found -# -def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath): - FileList = GetFiles(Root, SkipList, FullPath) - NewFileList = [] - for File in FileList: - ExtName = os.path.splitext(File)[1] - # - # skip '.dec', '.inf', '.dsc', '.fdf' files - # - if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']: - NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File))) - - return NewFileList - -## Check if given file exists or not -# -# @param File: File name or path to be checked -# @param Dir: The directory the file is relative to -# -def ValidFile(File, Ext=None): - File = File.replace('\\', '/') - if Ext != None: - FileExt = os.path.splitext(File)[1] - if FileExt.lower() != Ext.lower(): - return False - if not os.path.exists(File): - return False - return True - -## RealPath -# -# @param File: File name or path to be checked -# @param Dir: The directory the file is relative to -# @param OverrideDir: The override directory -# -def RealPath(File, Dir='', OverrideDir=''): - NewFile = os.path.normpath(os.path.join(Dir, File)) - NewFile = GlobalData.gALL_FILES[NewFile] - if not NewFile and OverrideDir: - NewFile = os.path.normpath(os.path.join(OverrideDir, File)) - NewFile = GlobalData.gALL_FILES[NewFile] - return NewFile - -## RealPath2 -# -# @param File: File name or path to be checked -# @param Dir: The directory the file is relative to -# @param OverrideDir: The override directory -# -def RealPath2(File, Dir='', OverrideDir=''): - if OverrideDir: - NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\ - (OverrideDir, File))] - if NewFile: - if OverrideDir[-1] == os.path.sep: - return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] - else: - return NewFile[len(OverrideDir) + 1:], \ - NewFile[0:len(OverrideDir)] - - NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))] - if NewFile: - if Dir: - if Dir[-1] == os.path.sep: - return NewFile[len(Dir):], NewFile[0:len(Dir)] - else: - return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] - else: - return NewFile, '' - - return None, None - -## A dict which can access its keys and/or values orderly -# -# The class implements a new kind of dict which its keys or values can be -# accessed in the order they are added into the dict. It guarantees the order -# by making use of an internal list to keep a copy of keys. -# -class Sdict(IterableUserDict): - ## Constructor - # - def __init__(self): - IterableUserDict.__init__(self) - self._key_list = [] - - ## [] operator - # - def __setitem__(self, Key, Value): - if Key not in self._key_list: - self._key_list.append(Key) - IterableUserDict.__setitem__(self, Key, Value) - - ## del operator - # - def __delitem__(self, Key): - self._key_list.remove(Key) - IterableUserDict.__delitem__(self, Key) - - ## used in "for k in dict" loop to ensure the correct order - # - def __iter__(self): - return self.iterkeys() - - ## len() support - # - def __len__(self): - return len(self._key_list) - - ## "in" test support - # - def __contains__(self, Key): - return Key in self._key_list - - ## indexof support - # - def index(self, Key): - return self._key_list.index(Key) - - ## insert support - # - def insert(self, Key, Newkey, Newvalue, Order): - Index = self._key_list.index(Key) - if Order == 'BEFORE': - self._key_list.insert(Index, Newkey) - IterableUserDict.__setitem__(self, Newkey, Newvalue) - elif Order == 'AFTER': - self._key_list.insert(Index + 1, Newkey) - IterableUserDict.__setitem__(self, Newkey, Newvalue) - - ## append support - # - def append(self, Sdict2): - for Key in Sdict2: - if Key not in self._key_list: - self._key_list.append(Key) - IterableUserDict.__setitem__(self, Key, Sdict2[Key]) - ## hash key - # - def has_key(self, Key): - return Key in self._key_list - - ## Empty the dict - # - def clear(self): - self._key_list = [] - IterableUserDict.clear(self) - - ## Return a copy of keys - # - def keys(self): - Keys = [] - for Key in self._key_list: - Keys.append(Key) - return Keys - - ## Return a copy of values - # - def values(self): - Values = [] - for Key in self._key_list: - Values.append(self[Key]) - return Values - - ## Return a copy of (key, value) list - # - def items(self): - Items = [] - for Key in self._key_list: - Items.append((Key, self[Key])) - return Items - - ## Iteration support - # - def iteritems(self): - return iter(self.items()) - - ## Keys interation support - # - def iterkeys(self): - return iter(self.keys()) - - ## Values interation support - # - def itervalues(self): - return iter(self.values()) - - ## Return value related to a key, and remove the (key, value) from the dict - # - def pop(self, Key, *Dv): - Value = None - if Key in self._key_list: - Value = self[Key] - self.__delitem__(Key) - elif len(Dv) != 0 : - Value = Dv[0] - return Value - - ## Return (key, value) pair, and remove the (key, value) from the dict - # - def popitem(self): - Key = self._key_list[-1] - Value = self[Key] - self.__delitem__(Key) - return Key, Value - ## update method - # - def update(self, Dict=None, **Kwargs): - if Dict != None: - for Key1, Val1 in Dict.items(): - self[Key1] = Val1 - if len(Kwargs): - for Key1, Val1 in Kwargs.items(): - self[Key1] = Val1 - -## CommonPath -# -# @param PathList: PathList -# -def CommonPath(PathList): - Path1 = min(PathList).split(os.path.sep) - Path2 = max(PathList).split(os.path.sep) - for Index in xrange(min(len(Path1), len(Path2))): - if Path1[Index] != Path2[Index]: - return os.path.sep.join(Path1[:Index]) - return os.path.sep.join(Path1) - -## PathClass -# -class PathClass(object): - def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, - Arch='COMMON', ToolChainFamily='', Target='', TagName='', \ - ToolCode=''): - self.Arch = Arch - self.File = str(File) - if os.path.isabs(self.File): - self.Root = '' - self.AlterRoot = '' - else: - self.Root = str(Root) - self.AlterRoot = str(AlterRoot) - - # - # Remove any '.' and '..' in path - # - if self.Root: - self.Path = os.path.normpath(os.path.join(self.Root, self.File)) - self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) - # - # eliminate the side-effect of 'C:' - # - if self.Root[-1] == ':': - self.Root += os.path.sep - # - # file path should not start with path separator - # - if self.Root[-1] == os.path.sep: - self.File = self.Path[len(self.Root):] - else: - self.File = self.Path[len(self.Root) + 1:] - else: - self.Path = os.path.normpath(self.File) - - self.SubDir, self.Name = os.path.split(self.File) - self.BaseName, self.Ext = os.path.splitext(self.Name) - - if self.Root: - if self.SubDir: - self.Dir = os.path.join(self.Root, self.SubDir) - else: - self.Dir = self.Root - else: - self.Dir = self.SubDir - - if IsBinary: - self.Type = Type - else: - self.Type = self.Ext.lower() - - self.IsBinary = IsBinary - self.Target = Target - self.TagName = TagName - self.ToolCode = ToolCode - self.ToolChainFamily = ToolChainFamily - - self._Key = None - - ## Convert the object of this class to a string - # - # Convert member Path of the class to a string - # - def __str__(self): - return self.Path - - ## Override __eq__ function - # - # Check whether PathClass are the same - # - def __eq__(self, Other): - if type(Other) == type(self): - return self.Path == Other.Path - else: - return self.Path == str(Other) - - ## Override __hash__ function - # - # Use Path as key in hash table - # - def __hash__(self): - return hash(self.Path) - - ## _GetFileKey - # - def _GetFileKey(self): - if self._Key == None: - self._Key = self.Path.upper() - return self._Key - ## Validate - # - def Validate(self, Type='', CaseSensitive=True): - if GlobalData.gCASE_INSENSITIVE: - CaseSensitive = False - if Type and Type.lower() != self.Type: - return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \ - (self.File, Type, self.Type) - - RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) - if not RealRoot and not RealFile: - RealFile = self.File - if self.AlterRoot: - RealFile = os.path.join(self.AlterRoot, self.File) - elif self.Root: - RealFile = os.path.join(self.Root, self.File) - return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) - - ErrorCode = 0 - ErrorInfo = '' - if RealRoot != self.Root or RealFile != self.File: - if CaseSensitive and (RealFile != self.File or \ - (RealRoot != self.Root and RealRoot != \ - self.AlterRoot)): - ErrorCode = ToolError.FILE_CASE_MISMATCH - ErrorInfo = self.File + '\n\t' + RealFile + \ - " [in file system]" - - self.SubDir, self.Name = os.path.split(RealFile) - self.BaseName, self.Ext = os.path.splitext(self.Name) - if self.SubDir: - self.Dir = os.path.join(RealRoot, self.SubDir) - else: - self.Dir = RealRoot - self.File = RealFile - self.Root = RealRoot - self.Path = os.path.join(RealRoot, RealFile) - return ErrorCode, ErrorInfo - - Key = property(_GetFileKey) - -## Check environment variables -# -# Check environment variables that must be set for build. Currently they are -# -# WORKSPACE The directory all packages/platforms start from -# EDK_TOOLS_PATH The directory contains all tools needed by the build -# PATH $(EDK_TOOLS_PATH)/Bin/ must be set in PATH -# -# If any of above environment variable is not set or has error, the build -# will be broken. -# -def CheckEnvVariable(): - # - # check WORKSPACE - # - if "WORKSPACE" not in environ: - Logger.Error("UPT", - ToolError.UPT_ENVIRON_MISSING_ERROR, - ST.ERR_NOT_FOUND_ENVIRONMENT, - ExtraData="WORKSPACE") - - WorkspaceDir = os.path.normpath(environ["WORKSPACE"]) - if not os.path.exists(WorkspaceDir): - Logger.Error("UPT", - ToolError.UPT_ENVIRON_MISSING_ERROR, - ST.ERR_WORKSPACE_NOTEXIST, - ExtraData="%s" % WorkspaceDir) - elif ' ' in WorkspaceDir: - Logger.Error("UPT", - ToolError.FORMAT_NOT_SUPPORTED, - ST.ERR_SPACE_NOTALLOWED, - ExtraData=WorkspaceDir) - -## Check whether all module types are in list -# -# check whether all module types (SUP_MODULE_LIST) are in list -# -# @param ModuleList: a list of ModuleType -# -def IsAllModuleList(ModuleList): - NewModuleList = [Module.upper() for Module in ModuleList] - for Module in SUP_MODULE_LIST: - if Module not in NewModuleList: - return False - else: - return True - -## Dictionary that use comment(GenericComment, TailComment) as value, -# if a new comment which key already in the dic is inserted, then the -# comment will be merged. -# Key is (Statement, SupArch), when TailComment is added, it will ident -# according to Statement -# -class MergeCommentDict(dict): - ## []= operator - # - def __setitem__(self, Key, CommentVal): - GenericComment, TailComment = CommentVal - if Key in self: - OrigVal1, OrigVal2 = dict.__getitem__(self, Key) - Statement = Key[0] - dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \ - + len(Statement) * ' ' + TailComment)) - else: - dict.__setitem__(self, Key, (GenericComment, TailComment)) - - ## =[] operator - # - def __getitem__(self, Key): - return dict.__getitem__(self, Key) - - -## GenDummyHelpTextObj -# -# @retval HelpTxt: Generated dummy help text object -# -def GenDummyHelpTextObj(): - HelpTxt = TextObject() - HelpTxt.SetLang(LANGUAGE_EN_US) - HelpTxt.SetString(' ') - return HelpTxt - -## ConvertVersionToDecimal, the minor version should be within 0 - 99 -# ::= "0x" -# ::= (a-fA-F0-9){4} -# ::= (a-fA-F0-9){4} -# ::= (0-65535) ["." (0-99)] -# -# @param StringIn: The string contains version defined in INF file. -# It can be Decimal or Hex -# -def ConvertVersionToDecimal(StringIn): - if IsValidHexVersion(StringIn): - Value = int(StringIn, 16) - Major = Value >> 16 - Minor = Value & 0xFFFF - MinorStr = str(Minor) - if len(MinorStr) == 1: - MinorStr = '0' + MinorStr - return str(Major) + '.' + MinorStr - else: - if StringIn.find(TAB_SPLIT) != -1: - return StringIn - elif StringIn: - return StringIn + '.0' - else: - # - # when StringIn is '', return it directly - # - return StringIn - -## GetHelpStringByRemoveHashKey -# -# Remove hash key at the header of string and return the remain. -# -# @param String: The string need to be processed. -# -def GetHelpStringByRemoveHashKey(String): - ReturnString = '' - PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL) - String = String.strip() - if String == '': - return String - - LineList = GetSplitValueList(String, END_OF_LINE) - for Line in LineList: - ValueList = PattenRemoveHashKey.split(Line) - if len(ValueList) == 1: - ReturnString += ValueList[0] + END_OF_LINE - else: - ReturnString += ValueList[1] + END_OF_LINE - - if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n': - ReturnString = ReturnString[:-1] - - return ReturnString - -## ConvPathFromAbsToRel -# -# Get relative file path from absolute path. -# -# @param Path: The string contain file absolute path. -# @param Root: The string contain the parent path of Path in. -# -# -def ConvPathFromAbsToRel(Path, Root): - Path = os.path.normpath(Path) - Root = os.path.normpath(Root) - FullPath = os.path.normpath(os.path.join(Root, Path)) - - # - # If Path is absolute path. - # It should be in Root. - # - if os.path.isabs(Path): - return FullPath[FullPath.find(Root) + len(Root) + 1:] - - else: - return Path - -## ConvertPath -# -# Convert special characters to '_', '\' to '/' -# return converted path: Test!1.inf -> Test_1.inf -# -# @param Path: Path to be converted -# -def ConvertPath(Path): - RetPath = '' - for Char in Path.strip(): - if Char.isalnum() or Char in '.-_/': - RetPath = RetPath + Char - elif Char == '\\': - RetPath = RetPath + '/' - else: - RetPath = RetPath + '_' - return RetPath - -## ConvertSpec -# -# during install, convert the Spec string extract from UPD into INF allowable definition, -# the difference is period is allowed in the former (not the first letter) but not in the latter. -# return converted Spec string -# -# @param SpecStr: SpecStr to be converted -# -def ConvertSpec(SpecStr): - RetStr = '' - for Char in SpecStr: - if Char.isalnum() or Char == '_': - RetStr = RetStr + Char - else: - RetStr = RetStr + '_' - - return RetStr - - -## IsEqualList -# -# Judge two lists are identical(contain same item). -# The rule is elements in List A are in List B and elements in List B are in List A. -# -# @param ListA, ListB Lists need to be judged. -# -# @return True ListA and ListB are identical -# @return False ListA and ListB are different with each other -# -def IsEqualList(ListA, ListB): - if ListA == ListB: - return True - - for ItemA in ListA: - if not ItemA in ListB: - return False - - for ItemB in ListB: - if not ItemB in ListA: - return False - - return True - -## ConvertArchList -# -# Convert item in ArchList if the start character is lower case. -# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* -# -# @param ArchList The ArchList need to be converted. -# -# @return NewList The ArchList been converted. -# -def ConvertArchList(ArchList): - NewArchList = [] - if not ArchList: - return NewArchList - - if type(ArchList) == list: - for Arch in ArchList: - Arch = Arch.upper() - NewArchList.append(Arch) - elif type(ArchList) == str: - ArchList = ArchList.upper() - NewArchList.append(ArchList) - - return NewArchList - -## ProcessLineExtender -# -# Process the LineExtender of Line in LineList. -# If one line ends with a line extender, then it will be combined together with next line. -# -# @param LineList The LineList need to be processed. -# -# @return NewList The ArchList been processed. -# -def ProcessLineExtender(LineList): - NewList = [] - Count = 0 - while Count < len(LineList): - if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList): - NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1]) - Count = Count + 1 - else: - NewList.append(LineList[Count]) - - Count = Count + 1 - - return NewList - -## ProcessEdkComment -# -# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment -# -# -# @param LineList The LineList need to be processed. -# -# @return LineList The LineList been processed. -# @return FirstPos Where Edk comment is first found, -1 if not found -# -def ProcessEdkComment(LineList): - FindEdkBlockComment = False - Count = 0 - StartPos = -1 - EndPos = -1 - FirstPos = -1 - - while(Count < len(LineList)): - Line = LineList[Count].strip() - if Line.startswith("/*"): - # - # handling c style comment - # - StartPos = Count - while Count < len(LineList): - Line = LineList[Count].strip() - if Line.endswith("*/"): - if (Count == StartPos) and Line.strip() == '/*/': - Count = Count + 1 - continue - EndPos = Count - FindEdkBlockComment = True - break - Count = Count + 1 - - if FindEdkBlockComment: - if FirstPos == -1: - FirstPos = StartPos - for Index in xrange(StartPos, EndPos+1): - LineList[Index] = '' - FindEdkBlockComment = False - elif Line.find("//") != -1: - # - # handling cpp style comment - # - LineList[Count] = Line.replace("//", '#') - if FirstPos == -1: - FirstPos = Count - - Count = Count + 1 - - return LineList, FirstPos - -## GetLibInstanceInfo -# -# Get the information from Library Instance INF file. -# -# @param string. A string start with # and followed by INF file path -# @param WorkSpace. The WorkSpace directory used to combined with INF file path. -# -# @return GUID, Version -def GetLibInstanceInfo(String, WorkSpace, LineNo): - - FileGuidString = "" - VerString = "" - - OrignalString = String - String = String.strip() - if not String: - return None, None - # - # Remove "#" characters at the beginning - # - String = GetHelpStringByRemoveHashKey(String) - String = String.strip() - - # - # Validate file name exist. - # - FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String))) - if not (ValidFile(FullFileName)): - Logger.Error("InfParser", - ToolError.FORMAT_INVALID, - ST.ERR_FILELIST_EXIST % (String), - File=GlobalData.gINF_MODULE_NAME, - Line=LineNo, - ExtraData=OrignalString) - - # - # Validate file exist/format. - # - if IsValidPath(String, WorkSpace): - IsValidFileFlag = True - else: - Logger.Error("InfParser", - ToolError.FORMAT_INVALID, - ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String), - File=GlobalData.gINF_MODULE_NAME, - Line=LineNo, - ExtraData=OrignalString) - return False - if IsValidFileFlag: - FileLinesList = [] - - try: - FInputfile = open(FullFileName, "rb", 0) - try: - FileLinesList = FInputfile.readlines() - except BaseException: - Logger.Error("InfParser", - ToolError.FILE_READ_FAILURE, - ST.ERR_FILE_OPEN_FAILURE, - File=FullFileName) - finally: - FInputfile.close() - except BaseException: - Logger.Error("InfParser", - ToolError.FILE_READ_FAILURE, - ST.ERR_FILE_OPEN_FAILURE, - File=FullFileName) - - ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") - ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") - - FileLinesList = ProcessLineExtender(FileLinesList) - - for Line in FileLinesList: - if ReFileGuidPattern.match(Line): - FileGuidString = Line - if ReVerStringPattern.match(Line): - VerString = Line - - if FileGuidString: - FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] - if VerString: - VerString = GetSplitValueList(VerString, '=', 1)[1] - - return FileGuidString, VerString +## @file +# Common routines used by all tools +# +# Copyright (c) 2011 - 2018, 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. +# + +''' +Misc +''' + +## +# Import Modules +# +import os.path +from os import access +from os import F_OK +from os import makedirs +from os import getcwd +from os import chdir +from os import listdir +from os import remove +from os import rmdir +from os import linesep +from os import walk +from os import environ +import re +from UserDict import IterableUserDict + +import Logger.Log as Logger +from Logger import StringTable as ST +from Logger import ToolError +from Library import GlobalData +from Library.DataType import SUP_MODULE_LIST +from Library.DataType import END_OF_LINE +from Library.DataType import TAB_SPLIT +from Library.DataType import TAB_LANGUAGE_EN_US +from Library.DataType import TAB_LANGUAGE_EN +from Library.DataType import TAB_LANGUAGE_EN_X +from Library.DataType import TAB_UNI_FILE_SUFFIXS +from Library.StringUtils import GetSplitValueList +from Library.ParserValidate import IsValidHexVersion +from Library.ParserValidate import IsValidPath +from Object.POM.CommonObject import TextObject +from Core.FileHook import __FileHookOpen__ +from Common.MultipleWorkspace import MultipleWorkspace as mws + +## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C +# structure style +# +# @param Guid: The GUID string +# +def GuidStringToGuidStructureString(Guid): + GuidList = Guid.split('-') + Result = '{' + for Index in range(0, 3, 1): + Result = Result + '0x' + GuidList[Index] + ', ' + Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4] + for Index in range(0, 12, 2): + Result = Result + ', 0x' + GuidList[4][Index:Index + 2] + Result += '}}' + return Result + +## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# +# @param GuidValue: The GUID value +# +def CheckGuidRegFormat(GuidValue): + ## Regular expression used to find out register format of GUID + # + RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-" + "([0-9a-fA-F]){4}-" + "([0-9a-fA-F]){4}-" + "([0-9a-fA-F]){4}-" + "([0-9a-fA-F]){12}\s*$") + + if RegFormatGuidPattern.match(GuidValue): + return True + else: + return False + + +## Convert GUID string in C structure style to +# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx +# +# @param GuidValue: The GUID value in C structure format +# +def GuidStructureStringToGuidString(GuidValue): + GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\ + replace(" ", "").replace(";", "") + GuidValueList = GuidValueString.split(",") + if len(GuidValueList) != 11: + return '' + try: + return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % ( + int(GuidValueList[0], 16), + int(GuidValueList[1], 16), + int(GuidValueList[2], 16), + int(GuidValueList[3], 16), + int(GuidValueList[4], 16), + int(GuidValueList[5], 16), + int(GuidValueList[6], 16), + int(GuidValueList[7], 16), + int(GuidValueList[8], 16), + int(GuidValueList[9], 16), + int(GuidValueList[10], 16) + ) + except BaseException: + return '' + +## Create directories +# +# @param Directory: The directory name +# +def CreateDirectory(Directory): + if Directory is None or Directory.strip() == "": + return True + try: + if not access(Directory, F_OK): + makedirs(Directory) + except BaseException: + return False + return True + +## Remove directories, including files and sub-directories in it +# +# @param Directory: The directory name +# +def RemoveDirectory(Directory, Recursively=False): + if Directory is None or Directory.strip() == "" or not \ + os.path.exists(Directory): + return + if Recursively: + CurrentDirectory = getcwd() + chdir(Directory) + for File in listdir("."): + if os.path.isdir(File): + RemoveDirectory(File, Recursively) + else: + remove(File) + chdir(CurrentDirectory) + rmdir(Directory) + +## Store content in file +# +# This method is used to save file only when its content is changed. This is +# quite useful for "make" system to decide what will be re-built and what +# won't. +# +# @param File: The path of file +# @param Content: The new content of the file +# @param IsBinaryFile: The flag indicating if the file is binary file +# or not +# +def SaveFileOnChange(File, Content, IsBinaryFile=True): + if not IsBinaryFile: + Content = Content.replace("\n", linesep) + + if os.path.exists(File): + try: + if Content == __FileHookOpen__(File, "rb").read(): + return False + except BaseException: + Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File) + + CreateDirectory(os.path.dirname(File)) + try: + FileFd = __FileHookOpen__(File, "wb") + FileFd.write(Content) + FileFd.close() + except BaseException: + Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File) + + return True + +## Get all files of a directory +# +# @param Root: Root dir +# @param SkipList : The files need be skipped +# +def GetFiles(Root, SkipList=None, FullPath=True): + OriPath = os.path.normpath(Root) + FileList = [] + for Root, Dirs, Files in walk(Root): + if SkipList: + for Item in SkipList: + if Item in Dirs: + Dirs.remove(Item) + if Item in Files: + Files.remove(Item) + for Dir in Dirs: + if Dir.startswith('.'): + Dirs.remove(Dir) + + for File in Files: + if File.startswith('.'): + continue + File = os.path.normpath(os.path.join(Root, File)) + if not FullPath: + File = File[len(OriPath) + 1:] + FileList.append(File) + + return FileList + +## Get all non-metadata files of a directory +# +# @param Root: Root Dir +# @param SkipList : List of path need be skipped +# @param FullPath: True if the returned file should be full path +# @param PrefixPath: the path that need to be added to the files found +# @return: the list of files found +# +def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath): + FileList = GetFiles(Root, SkipList, FullPath) + NewFileList = [] + for File in FileList: + ExtName = os.path.splitext(File)[1] + # + # skip '.dec', '.inf', '.dsc', '.fdf' files + # + if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']: + NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File))) + + return NewFileList + +## Check if given file exists or not +# +# @param File: File name or path to be checked +# @param Dir: The directory the file is relative to +# +def ValidFile(File, Ext=None): + File = File.replace('\\', '/') + if Ext is not None: + FileExt = os.path.splitext(File)[1] + if FileExt.lower() != Ext.lower(): + return False + if not os.path.exists(File): + return False + return True + +## RealPath +# +# @param File: File name or path to be checked +# @param Dir: The directory the file is relative to +# @param OverrideDir: The override directory +# +def RealPath(File, Dir='', OverrideDir=''): + NewFile = os.path.normpath(os.path.join(Dir, File)) + NewFile = GlobalData.gALL_FILES[NewFile] + if not NewFile and OverrideDir: + NewFile = os.path.normpath(os.path.join(OverrideDir, File)) + NewFile = GlobalData.gALL_FILES[NewFile] + return NewFile + +## RealPath2 +# +# @param File: File name or path to be checked +# @param Dir: The directory the file is relative to +# @param OverrideDir: The override directory +# +def RealPath2(File, Dir='', OverrideDir=''): + if OverrideDir: + NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\ + (OverrideDir, File))] + if NewFile: + if OverrideDir[-1] == os.path.sep: + return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)] + else: + return NewFile[len(OverrideDir) + 1:], \ + NewFile[0:len(OverrideDir)] + + NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))] + if NewFile: + if Dir: + if Dir[-1] == os.path.sep: + return NewFile[len(Dir):], NewFile[0:len(Dir)] + else: + return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)] + else: + return NewFile, '' + + return None, None + +## A dict which can access its keys and/or values orderly +# +# The class implements a new kind of dict which its keys or values can be +# accessed in the order they are added into the dict. It guarantees the order +# by making use of an internal list to keep a copy of keys. +# +class Sdict(IterableUserDict): + ## Constructor + # + def __init__(self): + IterableUserDict.__init__(self) + self._key_list = [] + + ## [] operator + # + def __setitem__(self, Key, Value): + if Key not in self._key_list: + self._key_list.append(Key) + IterableUserDict.__setitem__(self, Key, Value) + + ## del operator + # + def __delitem__(self, Key): + self._key_list.remove(Key) + IterableUserDict.__delitem__(self, Key) + + ## used in "for k in dict" loop to ensure the correct order + # + def __iter__(self): + return self.iterkeys() + + ## len() support + # + def __len__(self): + return len(self._key_list) + + ## "in" test support + # + def __contains__(self, Key): + return Key in self._key_list + + ## indexof support + # + def index(self, Key): + return self._key_list.index(Key) + + ## insert support + # + def insert(self, Key, Newkey, Newvalue, Order): + Index = self._key_list.index(Key) + if Order == 'BEFORE': + self._key_list.insert(Index, Newkey) + IterableUserDict.__setitem__(self, Newkey, Newvalue) + elif Order == 'AFTER': + self._key_list.insert(Index + 1, Newkey) + IterableUserDict.__setitem__(self, Newkey, Newvalue) + + ## append support + # + def append(self, Sdict2): + for Key in Sdict2: + if Key not in self._key_list: + self._key_list.append(Key) + IterableUserDict.__setitem__(self, Key, Sdict2[Key]) + ## hash key + # + def has_key(self, Key): + return Key in self._key_list + + ## Empty the dict + # + def clear(self): + self._key_list = [] + IterableUserDict.clear(self) + + ## Return a copy of keys + # + def keys(self): + Keys = [] + for Key in self._key_list: + Keys.append(Key) + return Keys + + ## Return a copy of values + # + def values(self): + Values = [] + for Key in self._key_list: + Values.append(self[Key]) + return Values + + ## Return a copy of (key, value) list + # + def items(self): + Items = [] + for Key in self._key_list: + Items.append((Key, self[Key])) + return Items + + ## Iteration support + # + def iteritems(self): + return iter(self.items()) + + ## Keys interation support + # + def iterkeys(self): + return iter(self.keys()) + + ## Values interation support + # + def itervalues(self): + return iter(self.values()) + + ## Return value related to a key, and remove the (key, value) from the dict + # + def pop(self, Key, *Dv): + Value = None + if Key in self._key_list: + Value = self[Key] + self.__delitem__(Key) + elif len(Dv) != 0 : + Value = Dv[0] + return Value + + ## Return (key, value) pair, and remove the (key, value) from the dict + # + def popitem(self): + Key = self._key_list[-1] + Value = self[Key] + self.__delitem__(Key) + return Key, Value + ## update method + # + def update(self, Dict=None, **Kwargs): + if Dict is not None: + for Key1, Val1 in Dict.items(): + self[Key1] = Val1 + if len(Kwargs): + for Key1, Val1 in Kwargs.items(): + self[Key1] = Val1 + +## CommonPath +# +# @param PathList: PathList +# +def CommonPath(PathList): + Path1 = min(PathList).split(os.path.sep) + Path2 = max(PathList).split(os.path.sep) + for Index in xrange(min(len(Path1), len(Path2))): + if Path1[Index] != Path2[Index]: + return os.path.sep.join(Path1[:Index]) + return os.path.sep.join(Path1) + +## PathClass +# +class PathClass(object): + def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False, + Arch='COMMON', ToolChainFamily='', Target='', TagName='', \ + ToolCode=''): + self.Arch = Arch + self.File = str(File) + if os.path.isabs(self.File): + self.Root = '' + self.AlterRoot = '' + else: + self.Root = str(Root) + self.AlterRoot = str(AlterRoot) + + # + # Remove any '.' and '..' in path + # + if self.Root: + self.Path = os.path.normpath(os.path.join(self.Root, self.File)) + self.Root = os.path.normpath(CommonPath([self.Root, self.Path])) + # + # eliminate the side-effect of 'C:' + # + if self.Root[-1] == ':': + self.Root += os.path.sep + # + # file path should not start with path separator + # + if self.Root[-1] == os.path.sep: + self.File = self.Path[len(self.Root):] + else: + self.File = self.Path[len(self.Root) + 1:] + else: + self.Path = os.path.normpath(self.File) + + self.SubDir, self.Name = os.path.split(self.File) + self.BaseName, self.Ext = os.path.splitext(self.Name) + + if self.Root: + if self.SubDir: + self.Dir = os.path.join(self.Root, self.SubDir) + else: + self.Dir = self.Root + else: + self.Dir = self.SubDir + + if IsBinary: + self.Type = Type + else: + self.Type = self.Ext.lower() + + self.IsBinary = IsBinary + self.Target = Target + self.TagName = TagName + self.ToolCode = ToolCode + self.ToolChainFamily = ToolChainFamily + + self._Key = None + + ## Convert the object of this class to a string + # + # Convert member Path of the class to a string + # + def __str__(self): + return self.Path + + ## Override __eq__ function + # + # Check whether PathClass are the same + # + def __eq__(self, Other): + if type(Other) == type(self): + return self.Path == Other.Path + else: + return self.Path == str(Other) + + ## Override __hash__ function + # + # Use Path as key in hash table + # + def __hash__(self): + return hash(self.Path) + + ## _GetFileKey + # + def _GetFileKey(self): + if self._Key is None: + self._Key = self.Path.upper() + return self._Key + ## Validate + # + def Validate(self, Type='', CaseSensitive=True): + if GlobalData.gCASE_INSENSITIVE: + CaseSensitive = False + if Type and Type.lower() != self.Type: + return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \ + (self.File, Type, self.Type) + + RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot) + if not RealRoot and not RealFile: + RealFile = self.File + if self.AlterRoot: + RealFile = os.path.join(self.AlterRoot, self.File) + elif self.Root: + RealFile = os.path.join(self.Root, self.File) + return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile) + + ErrorCode = 0 + ErrorInfo = '' + if RealRoot != self.Root or RealFile != self.File: + if CaseSensitive and (RealFile != self.File or \ + (RealRoot != self.Root and RealRoot != \ + self.AlterRoot)): + ErrorCode = ToolError.FILE_CASE_MISMATCH + ErrorInfo = self.File + '\n\t' + RealFile + \ + " [in file system]" + + self.SubDir, self.Name = os.path.split(RealFile) + self.BaseName, self.Ext = os.path.splitext(self.Name) + if self.SubDir: + self.Dir = os.path.join(RealRoot, self.SubDir) + else: + self.Dir = RealRoot + self.File = RealFile + self.Root = RealRoot + self.Path = os.path.join(RealRoot, RealFile) + return ErrorCode, ErrorInfo + + Key = property(_GetFileKey) + +## Get current workspace +# +# get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE +# +def GetWorkspace(): + # + # check WORKSPACE + # + if "WORKSPACE" in environ: + WorkspaceDir = os.path.normpath(environ["WORKSPACE"]) + if not os.path.exists(WorkspaceDir): + Logger.Error("UPT", + ToolError.UPT_ENVIRON_MISSING_ERROR, + ST.ERR_WORKSPACE_NOTEXIST, + ExtraData="%s" % WorkspaceDir) + else: + WorkspaceDir = os.getcwd() + + if WorkspaceDir[-1] == ':': + WorkspaceDir += os.sep + + PackagesPath = os.environ.get("PACKAGES_PATH") + mws.setWs(WorkspaceDir, PackagesPath) + + return WorkspaceDir, mws.PACKAGES_PATH + +## Get relative path +# +# use full path and workspace to get relative path +# the destination of this function is mainly to resolve the root path issue(like c: or c:\) +# +# @param Fullpath: a string of fullpath +# @param Workspace: a string of workspace +# +def GetRelativePath(Fullpath, Workspace): + + RelativePath = '' + if Workspace.endswith(os.sep): + RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace):] + else: + RelativePath = Fullpath[Fullpath.upper().find(Workspace.upper())+len(Workspace)+1:] + + return RelativePath + +## Check whether all module types are in list +# +# check whether all module types (SUP_MODULE_LIST) are in list +# +# @param ModuleList: a list of ModuleType +# +def IsAllModuleList(ModuleList): + NewModuleList = [Module.upper() for Module in ModuleList] + for Module in SUP_MODULE_LIST: + if Module not in NewModuleList: + return False + else: + return True + +## Dictionary that use comment(GenericComment, TailComment) as value, +# if a new comment which key already in the dic is inserted, then the +# comment will be merged. +# Key is (Statement, SupArch), when TailComment is added, it will ident +# according to Statement +# +class MergeCommentDict(dict): + ## []= operator + # + def __setitem__(self, Key, CommentVal): + GenericComment, TailComment = CommentVal + if Key in self: + OrigVal1, OrigVal2 = dict.__getitem__(self, Key) + Statement = Key[0] + dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \ + + len(Statement) * ' ' + TailComment)) + else: + dict.__setitem__(self, Key, (GenericComment, TailComment)) + + ## =[] operator + # + def __getitem__(self, Key): + return dict.__getitem__(self, Key) + + +## GenDummyHelpTextObj +# +# @retval HelpTxt: Generated dummy help text object +# +def GenDummyHelpTextObj(): + HelpTxt = TextObject() + HelpTxt.SetLang(TAB_LANGUAGE_EN_US) + HelpTxt.SetString(' ') + return HelpTxt + +## ConvertVersionToDecimal, the minor version should be within 0 - 99 +# ::= "0x" +# ::= (a-fA-F0-9){4} +# ::= (a-fA-F0-9){4} +# ::= (0-65535) ["." (0-99)] +# +# @param StringIn: The string contains version defined in INF file. +# It can be Decimal or Hex +# +def ConvertVersionToDecimal(StringIn): + if IsValidHexVersion(StringIn): + Value = int(StringIn, 16) + Major = Value >> 16 + Minor = Value & 0xFFFF + MinorStr = str(Minor) + if len(MinorStr) == 1: + MinorStr = '0' + MinorStr + return str(Major) + '.' + MinorStr + else: + if StringIn.find(TAB_SPLIT) != -1: + return StringIn + elif StringIn: + return StringIn + '.0' + else: + # + # when StringIn is '', return it directly + # + return StringIn + +## GetHelpStringByRemoveHashKey +# +# Remove hash key at the header of string and return the remain. +# +# @param String: The string need to be processed. +# +def GetHelpStringByRemoveHashKey(String): + ReturnString = '' + PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL) + String = String.strip() + if String == '': + return String + + LineList = GetSplitValueList(String, END_OF_LINE) + for Line in LineList: + ValueList = PattenRemoveHashKey.split(Line) + if len(ValueList) == 1: + ReturnString += ValueList[0] + END_OF_LINE + else: + ReturnString += ValueList[1] + END_OF_LINE + + if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n': + ReturnString = ReturnString[:-1] + + return ReturnString + +## ConvPathFromAbsToRel +# +# Get relative file path from absolute path. +# +# @param Path: The string contain file absolute path. +# @param Root: The string contain the parent path of Path in. +# +# +def ConvPathFromAbsToRel(Path, Root): + Path = os.path.normpath(Path) + Root = os.path.normpath(Root) + FullPath = os.path.normpath(os.path.join(Root, Path)) + + # + # If Path is absolute path. + # It should be in Root. + # + if os.path.isabs(Path): + return FullPath[FullPath.find(Root) + len(Root) + 1:] + + else: + return Path + +## ConvertPath +# +# Convert special characters to '_', '\' to '/' +# return converted path: Test!1.inf -> Test_1.inf +# +# @param Path: Path to be converted +# +def ConvertPath(Path): + RetPath = '' + for Char in Path.strip(): + if Char.isalnum() or Char in '.-_/': + RetPath = RetPath + Char + elif Char == '\\': + RetPath = RetPath + '/' + else: + RetPath = RetPath + '_' + return RetPath + +## ConvertSpec +# +# during install, convert the Spec string extract from UPD into INF allowable definition, +# the difference is period is allowed in the former (not the first letter) but not in the latter. +# return converted Spec string +# +# @param SpecStr: SpecStr to be converted +# +def ConvertSpec(SpecStr): + RetStr = '' + for Char in SpecStr: + if Char.isalnum() or Char == '_': + RetStr = RetStr + Char + else: + RetStr = RetStr + '_' + + return RetStr + + +## IsEqualList +# +# Judge two lists are identical(contain same item). +# The rule is elements in List A are in List B and elements in List B are in List A. +# +# @param ListA, ListB Lists need to be judged. +# +# @return True ListA and ListB are identical +# @return False ListA and ListB are different with each other +# +def IsEqualList(ListA, ListB): + if ListA == ListB: + return True + + for ItemA in ListA: + if not ItemA in ListB: + return False + + for ItemB in ListB: + if not ItemB in ListA: + return False + + return True + +## ConvertArchList +# +# Convert item in ArchList if the start character is lower case. +# In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])* +# +# @param ArchList The ArchList need to be converted. +# +# @return NewList The ArchList been converted. +# +def ConvertArchList(ArchList): + NewArchList = [] + if not ArchList: + return NewArchList + + if type(ArchList) == list: + for Arch in ArchList: + Arch = Arch.upper() + NewArchList.append(Arch) + elif type(ArchList) == str: + ArchList = ArchList.upper() + NewArchList.append(ArchList) + + return NewArchList + +## ProcessLineExtender +# +# Process the LineExtender of Line in LineList. +# If one line ends with a line extender, then it will be combined together with next line. +# +# @param LineList The LineList need to be processed. +# +# @return NewList The ArchList been processed. +# +def ProcessLineExtender(LineList): + NewList = [] + Count = 0 + while Count < len(LineList): + if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList): + NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1]) + Count = Count + 1 + else: + NewList.append(LineList[Count]) + + Count = Count + 1 + + return NewList + +## ProcessEdkComment +# +# Process EDK style comment in LineList: c style /* */ comment or cpp style // comment +# +# +# @param LineList The LineList need to be processed. +# +# @return LineList The LineList been processed. +# @return FirstPos Where Edk comment is first found, -1 if not found +# +def ProcessEdkComment(LineList): + FindEdkBlockComment = False + Count = 0 + StartPos = -1 + EndPos = -1 + FirstPos = -1 + + while(Count < len(LineList)): + Line = LineList[Count].strip() + if Line.startswith("/*"): + # + # handling c style comment + # + StartPos = Count + while Count < len(LineList): + Line = LineList[Count].strip() + if Line.endswith("*/"): + if (Count == StartPos) and Line.strip() == '/*/': + Count = Count + 1 + continue + EndPos = Count + FindEdkBlockComment = True + break + Count = Count + 1 + + if FindEdkBlockComment: + if FirstPos == -1: + FirstPos = StartPos + for Index in xrange(StartPos, EndPos+1): + LineList[Index] = '' + FindEdkBlockComment = False + elif Line.find("//") != -1 and not Line.startswith("#"): + # + # handling cpp style comment + # + LineList[Count] = Line.replace("//", '#') + if FirstPos == -1: + FirstPos = Count + + Count = Count + 1 + + return LineList, FirstPos + +## GetLibInstanceInfo +# +# Get the information from Library Instance INF file. +# +# @param string. A string start with # and followed by INF file path +# @param WorkSpace. The WorkSpace directory used to combined with INF file path. +# +# @return GUID, Version +def GetLibInstanceInfo(String, WorkSpace, LineNo): + + FileGuidString = "" + VerString = "" + + OrignalString = String + String = String.strip() + if not String: + return None, None + # + # Remove "#" characters at the beginning + # + String = GetHelpStringByRemoveHashKey(String) + String = String.strip() + + # + # Validate file name exist. + # + FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String))) + if not (ValidFile(FullFileName)): + Logger.Error("InfParser", + ToolError.FORMAT_INVALID, + ST.ERR_FILELIST_EXIST % (String), + File=GlobalData.gINF_MODULE_NAME, + Line=LineNo, + ExtraData=OrignalString) + + # + # Validate file exist/format. + # + if IsValidPath(String, WorkSpace): + IsValidFileFlag = True + else: + Logger.Error("InfParser", + ToolError.FORMAT_INVALID, + ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String), + File=GlobalData.gINF_MODULE_NAME, + Line=LineNo, + ExtraData=OrignalString) + return False + if IsValidFileFlag: + FileLinesList = [] + + try: + FInputfile = open(FullFileName, "rb", 0) + try: + FileLinesList = FInputfile.readlines() + except BaseException: + Logger.Error("InfParser", + ToolError.FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=FullFileName) + finally: + FInputfile.close() + except BaseException: + Logger.Error("InfParser", + ToolError.FILE_READ_FAILURE, + ST.ERR_FILE_OPEN_FAILURE, + File=FullFileName) + + ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$") + ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$") + + FileLinesList = ProcessLineExtender(FileLinesList) + + for Line in FileLinesList: + if ReFileGuidPattern.match(Line): + FileGuidString = Line + if ReVerStringPattern.match(Line): + VerString = Line + + if FileGuidString: + FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1] + if VerString: + VerString = GetSplitValueList(VerString, '=', 1)[1] + + return FileGuidString, VerString + +## GetLocalValue +# +# Generate the local value for INF and DEC file. If Lang attribute not present, then use this value. +# If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is +# "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en' +# if 'en' was not found, then use this value. +# If multiple entries of a tag exist which have the same language code, use the last entry. +# +# @param ValueList A list need to be processed. +# @param UseFirstValue: True to use the first value, False to use the last value +# +# @return LocalValue +def GetLocalValue(ValueList, UseFirstValue=False): + Value1 = '' + Value2 = '' + Value3 = '' + Value4 = '' + Value5 = '' + for (Key, Value) in ValueList: + if Key == TAB_LANGUAGE_EN_X: + if UseFirstValue: + if not Value1: + Value1 = Value + else: + Value1 = Value + if Key == TAB_LANGUAGE_EN_US: + if UseFirstValue: + if not Value2: + Value2 = Value + else: + Value2 = Value + if Key == TAB_LANGUAGE_EN: + if UseFirstValue: + if not Value3: + Value3 = Value + else: + Value3 = Value + if Key.startswith(TAB_LANGUAGE_EN): + if UseFirstValue: + if not Value4: + Value4 = Value + else: + Value4 = Value + if Key == '': + if UseFirstValue: + if not Value5: + Value5 = Value + else: + Value5 = Value + + if Value1: + return Value1 + if Value2: + return Value2 + if Value3: + return Value3 + if Value4: + return Value4 + if Value5: + return Value5 + + return '' + + +## GetCharIndexOutStr +# +# Get comment character index outside a string +# +# @param Line: The string to be checked +# @param CommentCharacter: Comment char, used to ignore comment content +# +# @retval Index +# +def GetCharIndexOutStr(CommentCharacter, Line): + # + # remove whitespace + # + Line = Line.strip() + + # + # Check whether comment character is in a string + # + InString = False + for Index in range(0, len(Line)): + if Line[Index] == '"': + InString = not InString + elif Line[Index] == CommentCharacter and InString : + pass + elif Line[Index] == CommentCharacter and (Index +1) < len(Line) and Line[Index+1] == CommentCharacter \ + and not InString : + return Index + return -1 + +## ValidateUNIFilePath +# +# Check the UNI file path +# +# @param FilePath: The UNI file path +# +def ValidateUNIFilePath(Path): + Suffix = Path[Path.rfind(TAB_SPLIT):] + + # + # Check if the suffix is one of the '.uni', '.UNI', '.Uni' + # + if Suffix not in TAB_UNI_FILE_SUFFIXS: + Logger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + Message=ST.ERR_UNI_FILE_SUFFIX_WRONG, + ExtraData=Path) + + # + # Check if '..' in the file name(without suffixe) + # + if (TAB_SPLIT + TAB_SPLIT) in Path: + Logger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + Message=ST.ERR_UNI_FILE_NAME_INVALID, + ExtraData=Path) + + # + # Check if the file name is valid according to the DEC and INF specification + # + Pattern = '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*' + FileName = Path.replace(Suffix, '') + InvalidCh = re.sub(Pattern, '', FileName) + if InvalidCh: + Logger.Error("Unicode File Parser", + ToolError.FORMAT_INVALID, + Message=ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID, + ExtraData=Path) +