X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=BaseTools%2FSource%2FPython%2FCommon%2FString.py;h=5e50beff5cc39539a0eab1684d0281b0533b9918;hp=195fa5c6cacc0c9d82f483ace03316d04ae67ac2;hb=ea927d2f3f2e34f4b26c10829f5887830cb0720e;hpb=08dd311f5dc735c595d39faf2e6f7e2810bb79a9 diff --git a/BaseTools/Source/Python/Common/String.py b/BaseTools/Source/Python/Common/String.py index 195fa5c6ca..5e50beff5c 100644 --- a/BaseTools/Source/Python/Common/String.py +++ b/BaseTools/Source/Python/Common/String.py @@ -1,7 +1,7 @@ ## @file # This file is used to define common string related functions used in parsing process # -# Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2015, 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 @@ -16,14 +16,17 @@ # import re import DataType -import os.path +import Common.LongFilePathOs as os import string import EdkLogger as EdkLogger -from GlobalData import * +import GlobalData from BuildToolError import * +from CommonDataClass.Exceptions import * +from Common.LongFilePathSupport import OpenLongFilePath as open +from Common.MultipleWorkspace import MultipleWorkspace as mws -gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$',re.IGNORECASE) +gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE) gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') ## GetSplitValueList @@ -38,8 +41,64 @@ gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$') # # @retval list() A list for splitted string # -def GetSplitValueList(String, SplitTag = DataType.TAB_VALUE_SPLIT, MaxSplit = -1): - return map(lambda l: l.strip(), String.split(SplitTag, MaxSplit)) +def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): + ValueList = [] + Last = 0 + Escaped = False + InSingleQuoteString = False + InDoubleQuoteString = False + InParenthesis = 0 + for Index in range(0, len(String)): + Char = String[Index] + + if not Escaped: + # Found a splitter not in a string, split it + if (not InSingleQuoteString or not InDoubleQuoteString) and InParenthesis == 0 and Char == SplitTag: + ValueList.append(String[Last:Index].strip()) + Last = Index + 1 + if MaxSplit > 0 and len(ValueList) >= MaxSplit: + break + + if Char == '\\' and (InSingleQuoteString or InDoubleQuoteString): + Escaped = True + elif Char == '"' and not InSingleQuoteString: + if not InDoubleQuoteString: + InDoubleQuoteString = True + else: + InDoubleQuoteString = False + elif Char == "'" and not InDoubleQuoteString: + if not InSingleQuoteString: + InSingleQuoteString = True + else: + InSingleQuoteString = False + elif Char == '(': + InParenthesis = InParenthesis + 1 + elif Char == ')': + InParenthesis = InParenthesis - 1 + else: + Escaped = False + + if Last < len(String): + ValueList.append(String[Last:].strip()) + elif Last == len(String): + ValueList.append('') + + return ValueList + +## GetSplitList +# +# Get a value list from a string with multiple values splited with SplitString +# The default SplitTag is DataType.TAB_VALUE_SPLIT +# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC'] +# +# @param String: The input string to be splitted +# @param SplitStr: The split key, default is DataType.TAB_VALUE_SPLIT +# @param MaxSplit: The max number of split values, default is -1 +# +# @retval list() A list for splitted string +# +def GetSplitList(String, SplitStr=DataType.TAB_VALUE_SPLIT, MaxSplit= -1): + return map(lambda l: l.strip(), String.split(SplitStr, MaxSplit)) ## MergeArches # @@ -189,7 +248,7 @@ def SplitModuleType(Key): # # @retval NewList A new string list whose macros are replaced # -def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement = False): +def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement=False): NewList = [] for String in StringList: if type(String) == type(''): @@ -210,20 +269,23 @@ def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement = False): # # @retval string The string whose macros are replaced # -def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement = False): +def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement=False, RaiseError=False): LastString = String - while MacroDefinitions: - MacroUsed = gMacroPattern.findall(String) + while String and MacroDefinitions: + MacroUsed = GlobalData.gMacroRefPattern.findall(String) # no macro found in String, stop replacing if len(MacroUsed) == 0: break for Macro in MacroUsed: if Macro not in MacroDefinitions: + if RaiseError: + raise SymbolNotFound("%s not defined" % Macro) if SelfReplacement: String = String.replace("$(%s)" % Macro, '') continue - String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro]) + if "$(%s)" % Macro not in MacroDefinitions[Macro]: + String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro]) # in case there's macro not defined if String == LastString: break @@ -241,7 +303,7 @@ def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement = False): # # @retval Path Formatted path # -def NormPath(Path, Defines = {}): +def NormPath(Path, Defines={}): IsRelativePath = False if Path: if Path[0] == '.': @@ -255,6 +317,11 @@ def NormPath(Path, Defines = {}): # To local path format # Path = os.path.normpath(Path) + if Path.startswith(GlobalData.gWorkspace) and not Path.startswith(GlobalData.gBuildDirectory) and not os.path.exists(Path): + Path = Path[len (GlobalData.gWorkspace):] + if Path[0] == os.path.sep: + Path = Path[1:] + Path = mws.join(GlobalData.gWorkspace, Path) if IsRelativePath and Path[0] != '.': Path = os.path.join('.', Path) @@ -271,27 +338,49 @@ def NormPath(Path, Defines = {}): # # @retval Path Formatted path # -def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): +def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False): # # remove whitespace # Line = Line.strip(); # - # Replace R8's comment character + # Replace Edk's comment character # if AllowCppStyleComment: - Line = Line.replace(DataType.TAB_COMMENT_R8_SPLIT, CommentCharacter) + Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) # # remove comments, but we should escape comment character in string # - InString = False + InDoubleQuoteString = False + InSingleQuoteString = False + CommentInString = False for Index in range(0, len(Line)): - if Line[Index] == '"': - InString = not InString - elif Line[Index] == CommentCharacter and not InString: + if Line[Index] == '"' and not InSingleQuoteString: + InDoubleQuoteString = not InDoubleQuoteString + elif Line[Index] == "'" and not InDoubleQuoteString: + InSingleQuoteString = not InSingleQuoteString + elif Line[Index] == CommentCharacter and (InSingleQuoteString or InDoubleQuoteString): + CommentInString = True + elif Line[Index] == CommentCharacter and not (InSingleQuoteString or InDoubleQuoteString): Line = Line[0: Index] break - + + if CommentInString and BuildOption: + Line = Line.replace('"', '') + ChIndex = Line.find('#') + while ChIndex >= 0: + if GlobalData.gIsWindows: + if ChIndex == 0 or Line[ChIndex - 1] != '^': + Line = Line[0:ChIndex] + '^' + Line[ChIndex:] + ChIndex = Line.find('#', ChIndex + 2) + else: + ChIndex = Line.find('#', ChIndex + 1) + else: + if ChIndex == 0 or Line[ChIndex - 1] != '\\': + Line = Line[0:ChIndex] + '\\' + Line[ChIndex:] + ChIndex = Line.find('#', ChIndex + 2) + else: + ChIndex = Line.find('#', ChIndex + 1) # # remove whitespace again # @@ -301,7 +390,7 @@ def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSty ## CleanString2 # -# Split comments in a string +# Split statement with comments in a string # Remove spaces # # @param Line: The string to be cleaned @@ -309,37 +398,34 @@ def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSty # # @retval Path Formatted path # -def CleanString2(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): +def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False): # # remove whitespace # Line = Line.strip(); # - # Replace R8's comment character + # Replace Edk's comment character # if AllowCppStyleComment: - Line = Line.replace(DataType.TAB_COMMENT_R8_SPLIT, CommentCharacter) - # - # separate comments and statements - # - LineParts = Line.split(CommentCharacter, 1); + Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter) # - # remove whitespace again + # separate comments and statements, but we should escape comment character in string # - Line = LineParts[0].strip(); - if len(LineParts) > 1: - Comment = LineParts[1].strip() - # Remove prefixed and trailing comment characters - Start = 0 - End = len(Comment) - while Start < End and Comment.startswith(CommentCharacter, Start, End): - Start += 1 - while End >= 0 and Comment.endswith(CommentCharacter, Start, End): - End -= 1 - Comment = Comment[Start:End] - Comment = Comment.strip() - else: - Comment = '' + InDoubleQuoteString = False + InSingleQuoteString = False + CommentInString = False + Comment = '' + for Index in range(0, len(Line)): + if Line[Index] == '"' and not InSingleQuoteString: + InDoubleQuoteString = not InDoubleQuoteString + elif Line[Index] == "'" and not InDoubleQuoteString: + InSingleQuoteString = not InSingleQuoteString + elif Line[Index] == CommentCharacter and (InDoubleQuoteString or InSingleQuoteString): + CommentInString = True + elif Line[Index] == CommentCharacter and not (InDoubleQuoteString or InSingleQuoteString): + Comment = Line[Index:].strip() + Line = Line[0:Index].strip() + break return Line, Comment @@ -401,7 +487,7 @@ def GetHexVerValue(VerString): if len(Minor) == 1: Minor += '0' DeciValue = (int(Major) << 16) + int(Minor); - return "0x%08x"%DeciValue + return "0x%08x" % DeciValue elif gHexVerPatt.match(VerString): return VerString else: @@ -511,7 +597,7 @@ def PreCheck(FileName, FileContent, SupSectionTag): # if Line.find('$') > -1: if Line.find('$(') < 0 or Line.find(')') < 0: - EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError = EdkLogger.IsRaiseError) + EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) # # Check [] @@ -521,7 +607,7 @@ def PreCheck(FileName, FileContent, SupSectionTag): # Only get one '[' or one ']' # if not (Line.find('[') > -1 and Line.find(']') > -1): - EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError = EdkLogger.IsRaiseError) + EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) # # Regenerate FileContent @@ -529,7 +615,7 @@ def PreCheck(FileName, FileContent, SupSectionTag): NewFileContent = NewFileContent + Line + '\r\n' if IsFailed: - EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError = EdkLogger.IsRaiseError) + EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError) return NewFileContent @@ -547,7 +633,7 @@ def PreCheck(FileName, FileContent, SupSectionTag): # # @retval True The file type is correct # -def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo = -1): +def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1): if CheckFilename != '' and CheckFilename != None: (Root, Ext) = os.path.splitext(CheckFilename) if Ext.upper() != ExtName.upper(): @@ -556,7 +642,7 @@ def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo = GetLineNo(ContainerFile, Line) ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName) EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, - File=ContainerFilename, RaiseError = EdkLogger.IsRaiseError) + File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError) return True @@ -574,7 +660,7 @@ def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, # # @retval The file full path if the file exists # -def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo = -1): +def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1): CheckFile = '' if CheckFilename != '' and CheckFilename != None: CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename) @@ -584,7 +670,7 @@ def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, LineNo = GetLineNo(ContainerFile, Line) ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName) EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, - File=ContainerFilename, Line = LineNo, RaiseError = EdkLogger.IsRaiseError) + File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError) return CheckFile @@ -598,7 +684,7 @@ def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, # @retval int Index of the line # @retval -1 The line is not found # -def GetLineNo(FileContent, Line, IsIgnoreComment = True): +def GetLineNo(FileContent, Line, IsIgnoreComment=True): LineList = FileContent.splitlines() for Index in range(len(LineList)): if LineList[Index].find(Line) > -1: @@ -621,13 +707,13 @@ def GetLineNo(FileContent, Line, IsIgnoreComment = True): # @param File: File which has the string # @param Format: Correct format # -def RaiseParserError(Line, Section, File, Format = '', LineNo = -1): +def RaiseParserError(Line, Section, File, Format='', LineNo= -1): if LineNo == -1: LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line) ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section) if Format != '': Format = "Correct format is " + Format - EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError = EdkLogger.IsRaiseError) + EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError) ## WorkspaceFile # @@ -639,7 +725,7 @@ def RaiseParserError(Line, Section, File, Format = '', LineNo = -1): # @retval string A full path # def WorkspaceFile(WorkspaceDir, Filename): - return os.path.join(NormPath(WorkspaceDir), NormPath(Filename)) + return mws.join(NormPath(WorkspaceDir), NormPath(Filename)) ## Split string # @@ -689,11 +775,11 @@ def RemoveBlockComment(Lines): # # Remove comment block # - if Line.find(DataType.TAB_COMMENT_R8_START) > -1: - ReservedLine = GetSplitValueList(Line, DataType.TAB_COMMENT_R8_START, 1)[0] + if Line.find(DataType.TAB_COMMENT_EDK_START) > -1: + ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0] IsFindBlockComment = True - if Line.find(DataType.TAB_COMMENT_R8_END) > -1: - Line = ReservedLine + GetSplitValueList(Line, DataType.TAB_COMMENT_R8_END, 1)[1] + if Line.find(DataType.TAB_COMMENT_EDK_END) > -1: + Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1] ReservedLine = '' IsFindBlockComment = False if IsFindBlockComment: @@ -706,7 +792,7 @@ def RemoveBlockComment(Lines): # # Get String of a List # -def GetStringOfList(List, Split = ' '): +def GetStringOfList(List, Split=' '): if type(List) != type([]): return List Str = '' @@ -730,7 +816,7 @@ def GetHelpTextList(HelpTextClassList): def StringToArray(String): if isinstance(String, unicode): - if len(unicode) ==0: + if len(unicode) == 0: return "{0x00, 0x00}" return "{%s, 0x00, 0x00}" % ", ".join(["0x%02x, 0x00" % ord(C) for C in String]) elif String.startswith('L"'): @@ -740,11 +826,25 @@ def StringToArray(String): return "{%s, 0x00, 0x00}" % ", ".join(["0x%02x, 0x00" % ord(C) for C in String[2:-1]]) elif String.startswith('"'): if String == "\"\"": - return "{0x00}"; + return "{0x00,0x00}" else: - return "{%s, 0x00}" % ", ".join(["0x%02x" % ord(C) for C in String[1:-1]]) + StringLen = len(String[1:-1]) + if StringLen % 2: + return "{%s, 0x00}" % ", ".join(["0x%02x" % ord(C) for C in String[1:-1]]) + else: + return "{%s, 0x00,0x00}" % ", ".join(["0x%02x" % ord(C) for C in String[1:-1]]) + elif String.startswith('{'): + StringLen = len(String.split(",")) + if StringLen % 2: + return "{%s, 0x00}" % ", ".join([ C for C in String[1:-1].split(',')]) + else: + return "{%s}" % ", ".join([ C for C in String[1:-1].split(',')]) + else: - return '{%s, 0}' % ', '.join(String.split()) + if len(String.split()) % 2: + return '{%s, 0}' % ', '.join(String.split()) + else: + return '{%s, 0,0}' % ', '.join(String.split()) def StringArrayLength(String): if isinstance(String, unicode): @@ -755,7 +855,7 @@ def StringArrayLength(String): return (len(String) - 2 + 1) else: return len(String.split()) + 1 - + def RemoveDupOption(OptionString, Which="/I", Against=None): OptionList = OptionString.split() ValueList = []