]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/Common/String.py
Sync BaseTool trunk (version r2599) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / Python / Common / String.py
index 195fa5c6cacc0c9d82f483ace03316d04ae67ac2..c282326677f6f49d6b58fc5fb0adc424d8dc6901 100644 (file)
@@ -20,10 +20,11 @@ import os.path
 import string\r
 import EdkLogger as EdkLogger\r
 \r
-from GlobalData import *\r
+import GlobalData\r
 from BuildToolError import *\r
+from CommonDataClass.Exceptions import *\r
 \r
-gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$',re.IGNORECASE)\r
+gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE)\r
 gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')\r
 \r
 ## GetSplitValueList\r
@@ -38,8 +39,53 @@ gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')
 #\r
 # @retval list() A list for splitted string\r
 #\r
-def GetSplitValueList(String, SplitTag = DataType.TAB_VALUE_SPLIT, MaxSplit = -1):\r
-    return map(lambda l: l.strip(), String.split(SplitTag, MaxSplit))\r
+def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):\r
+    ValueList = []\r
+    Last = 0\r
+    Escaped = False\r
+    InString = False\r
+    for Index in range(0, len(String)):\r
+        Char = String[Index]\r
+\r
+        if not Escaped:\r
+            # Found a splitter not in a string, split it\r
+            if not InString and Char == SplitTag:\r
+                ValueList.append(String[Last:Index].strip())\r
+                Last = Index + 1\r
+                if MaxSplit > 0 and len(ValueList) >= MaxSplit:\r
+                    break\r
+\r
+            if Char == '\\' and InString:\r
+                Escaped = True\r
+            elif Char == '"':\r
+                if not InString:\r
+                    InString = True\r
+                else:\r
+                    InString = False\r
+        else:\r
+            Escaped = False\r
+\r
+    if Last < len(String):\r
+        ValueList.append(String[Last:].strip())\r
+    elif Last == len(String):\r
+        ValueList.append('')\r
+\r
+    return ValueList\r
+\r
+## GetSplitList\r
+#\r
+# Get a value list from a string with multiple values splited with SplitString\r
+# The default SplitTag is DataType.TAB_VALUE_SPLIT\r
+# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']\r
+#\r
+# @param String:    The input string to be splitted\r
+# @param SplitStr:  The split key, default is DataType.TAB_VALUE_SPLIT\r
+# @param MaxSplit:  The max number of split values, default is -1\r
+#\r
+# @retval list() A list for splitted string\r
+#\r
+def GetSplitList(String, SplitStr=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):\r
+    return map(lambda l: l.strip(), String.split(SplitStr, MaxSplit))\r
 \r
 ## MergeArches\r
 #\r
@@ -189,7 +235,7 @@ def SplitModuleType(Key):
 #\r
 # @retval NewList           A new string list whose macros are replaced\r
 #\r
-def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement = False):\r
+def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement=False):\r
     NewList = []\r
     for String in StringList:\r
         if type(String) == type(''):\r
@@ -210,16 +256,18 @@ def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement = False):
 #\r
 # @retval string            The string whose macros are replaced\r
 #\r
-def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement = False):\r
+def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement=False, RaiseError=False):\r
     LastString = String\r
-    while MacroDefinitions:\r
-        MacroUsed = gMacroPattern.findall(String)\r
+    while String and MacroDefinitions:\r
+        MacroUsed = GlobalData.gMacroRefPattern.findall(String)\r
         # no macro found in String, stop replacing\r
         if len(MacroUsed) == 0:\r
             break\r
 \r
         for Macro in MacroUsed:\r
             if Macro not in MacroDefinitions:\r
+                if RaiseError:\r
+                    raise SymbolNotFound("%s not defined" % Macro)\r
                 if SelfReplacement:\r
                     String = String.replace("$(%s)" % Macro, '')\r
                 continue\r
@@ -241,7 +289,7 @@ def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement = False):
 #\r
 # @retval Path Formatted path\r
 #\r
-def NormPath(Path, Defines = {}):\r
+def NormPath(Path, Defines={}):\r
     IsRelativePath = False\r
     if Path:\r
         if Path[0] == '.':\r
@@ -271,27 +319,46 @@ def NormPath(Path, Defines = {}):
 #\r
 # @retval Path Formatted path\r
 #\r
-def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):\r
+def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False):\r
     #\r
     # remove whitespace\r
     #\r
     Line = Line.strip();\r
     #\r
-    # Replace R8's comment character\r
+    # Replace Edk's comment character\r
     #\r
     if AllowCppStyleComment:\r
-        Line = Line.replace(DataType.TAB_COMMENT_R8_SPLIT, CommentCharacter)\r
+        Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)\r
     #\r
     # remove comments, but we should escape comment character in string\r
     #\r
     InString = False\r
+    CommentInString = False\r
     for Index in range(0, len(Line)):\r
         if Line[Index] == '"':\r
             InString = not InString\r
-        elif Line[Index] == CommentCharacter and not InString:\r
+        elif Line[Index] == CommentCharacter and InString :\r
+            CommentInString = True\r
+        elif Line[Index] == CommentCharacter and not InString :\r
             Line = Line[0: Index]\r
             break\r
-    \r
+\r
+    if CommentInString and BuildOption:\r
+        Line = Line.replace('"', '')\r
+        ChIndex = Line.find('#')\r
+        while ChIndex >= 0:\r
+            if GlobalData.gIsWindows:\r
+                if ChIndex == 0 or Line[ChIndex - 1] != '^':\r
+                    Line = Line[0:ChIndex] + '^' + Line[ChIndex:]\r
+                    ChIndex = Line.find('#', ChIndex + 2)\r
+                else:\r
+                    ChIndex = Line.find('#', ChIndex + 1)\r
+            else:\r
+                if ChIndex == 0 or Line[ChIndex - 1] != '\\':\r
+                    Line = Line[0:ChIndex] + '\\' + Line[ChIndex:]\r
+                    ChIndex = Line.find('#', ChIndex + 2)\r
+                else:\r
+                    ChIndex = Line.find('#', ChIndex + 1)\r
     #\r
     # remove whitespace again\r
     #\r
@@ -301,7 +368,7 @@ def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSty
 \r
 ## CleanString2\r
 #\r
-# Split comments in a string\r
+# Split statement with comments in a string\r
 # Remove spaces\r
 #\r
 # @param Line:              The string to be cleaned\r
@@ -309,26 +376,32 @@ def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSty
 #\r
 # @retval Path Formatted path\r
 #\r
-def CleanString2(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):\r
+def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):\r
     #\r
     # remove whitespace\r
     #\r
     Line = Line.strip();\r
     #\r
-    # Replace R8's comment character\r
+    # Replace Edk's comment character\r
     #\r
     if AllowCppStyleComment:\r
-        Line = Line.replace(DataType.TAB_COMMENT_R8_SPLIT, CommentCharacter)\r
+        Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)\r
     #\r
-    # separate comments and statements\r
+    # separate comments and statements, but we should escape comment character in string\r
     #\r
-    LineParts = Line.split(CommentCharacter, 1);\r
-    #\r
-    # remove whitespace again\r
-    #\r
-    Line = LineParts[0].strip();\r
-    if len(LineParts) > 1:\r
-        Comment = LineParts[1].strip()\r
+    InString = False\r
+    CommentInString = False\r
+    Comment = ''\r
+    for Index in range(0, len(Line)):\r
+        if Line[Index] == '"':\r
+            InString = not InString\r
+        elif Line[Index] == CommentCharacter and InString:\r
+            CommentInString = True\r
+        elif Line[Index] == CommentCharacter and not InString:\r
+            Comment = Line[Index:].strip()\r
+            Line = Line[0:Index].strip()\r
+            break\r
+    if Comment:\r
         # Remove prefixed and trailing comment characters\r
         Start = 0\r
         End = len(Comment)\r
@@ -338,8 +411,6 @@ def CleanString2(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSt
             End -= 1\r
         Comment = Comment[Start:End]\r
         Comment = Comment.strip()\r
-    else:\r
-        Comment = ''\r
 \r
     return Line, Comment\r
 \r
@@ -401,7 +472,7 @@ def GetHexVerValue(VerString):
         if len(Minor) == 1:\r
             Minor += '0'\r
         DeciValue = (int(Major) << 16) + int(Minor);\r
-        return "0x%08x"%DeciValue\r
+        return "0x%08x" % DeciValue\r
     elif gHexVerPatt.match(VerString):\r
         return VerString\r
     else:\r
@@ -511,7 +582,7 @@ def PreCheck(FileName, FileContent, SupSectionTag):
         #\r
         if Line.find('$') > -1:\r
             if Line.find('$(') < 0 or Line.find(')') < 0:\r
-                EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError = EdkLogger.IsRaiseError)\r
+                EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)\r
 \r
         #\r
         # Check []\r
@@ -521,7 +592,7 @@ def PreCheck(FileName, FileContent, SupSectionTag):
             # Only get one '[' or one ']'\r
             #\r
             if not (Line.find('[') > -1 and Line.find(']') > -1):\r
-                EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError = EdkLogger.IsRaiseError)\r
+                EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)\r
 \r
         #\r
         # Regenerate FileContent\r
@@ -529,7 +600,7 @@ def PreCheck(FileName, FileContent, SupSectionTag):
         NewFileContent = NewFileContent + Line + '\r\n'\r
 \r
     if IsFailed:\r
-       EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError = EdkLogger.IsRaiseError)\r
+       EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)\r
 \r
     return NewFileContent\r
 \r
@@ -547,7 +618,7 @@ def PreCheck(FileName, FileContent, SupSectionTag):
 #\r
 # @retval True The file type is correct\r
 #\r
-def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo = -1):\r
+def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1):\r
     if CheckFilename != '' and CheckFilename != None:\r
         (Root, Ext) = os.path.splitext(CheckFilename)\r
         if Ext.upper() != ExtName.upper():\r
@@ -556,7 +627,7 @@ def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line,
                 LineNo = GetLineNo(ContainerFile, Line)\r
             ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName)\r
             EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo,\r
-                            File=ContainerFilename, RaiseError = EdkLogger.IsRaiseError)\r
+                            File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError)\r
 \r
     return True\r
 \r
@@ -574,7 +645,7 @@ def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line,
 #\r
 # @retval The file full path if the file exists\r
 #\r
-def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo = -1):\r
+def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1):\r
     CheckFile = ''\r
     if CheckFilename != '' and CheckFilename != None:\r
         CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename)\r
@@ -584,7 +655,7 @@ def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName,
                 LineNo = GetLineNo(ContainerFile, Line)\r
             ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName)\r
             EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg,\r
-                            File=ContainerFilename, Line = LineNo, RaiseError = EdkLogger.IsRaiseError)\r
+                            File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError)\r
 \r
     return CheckFile\r
 \r
@@ -598,7 +669,7 @@ def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName,
 # @retval int  Index of the line\r
 # @retval -1     The line is not found\r
 #\r
-def GetLineNo(FileContent, Line, IsIgnoreComment = True):\r
+def GetLineNo(FileContent, Line, IsIgnoreComment=True):\r
     LineList = FileContent.splitlines()\r
     for Index in range(len(LineList)):\r
         if LineList[Index].find(Line) > -1:\r
@@ -621,13 +692,13 @@ def GetLineNo(FileContent, Line, IsIgnoreComment = True):
 # @param File:     File which has the string\r
 # @param Format:   Correct format\r
 #\r
-def RaiseParserError(Line, Section, File, Format = '', LineNo = -1):\r
+def RaiseParserError(Line, Section, File, Format='', LineNo= -1):\r
     if LineNo == -1:\r
         LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line)\r
     ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section)\r
     if Format != '':\r
         Format = "Correct format is " + Format\r
-    EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError = EdkLogger.IsRaiseError)\r
+    EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError)\r
 \r
 ## WorkspaceFile\r
 #\r
@@ -689,11 +760,11 @@ def RemoveBlockComment(Lines):
         #\r
         # Remove comment block\r
         #\r
-        if Line.find(DataType.TAB_COMMENT_R8_START) > -1:\r
-            ReservedLine = GetSplitValueList(Line, DataType.TAB_COMMENT_R8_START, 1)[0]\r
+        if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:\r
+            ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0]\r
             IsFindBlockComment = True\r
-        if Line.find(DataType.TAB_COMMENT_R8_END) > -1:\r
-            Line = ReservedLine + GetSplitValueList(Line, DataType.TAB_COMMENT_R8_END, 1)[1]\r
+        if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:\r
+            Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1]\r
             ReservedLine = ''\r
             IsFindBlockComment = False\r
         if IsFindBlockComment:\r
@@ -706,7 +777,7 @@ def RemoveBlockComment(Lines):
 #\r
 # Get String of a List\r
 #\r
-def GetStringOfList(List, Split = ' '):\r
+def GetStringOfList(List, Split=' '):\r
     if type(List) != type([]):\r
         return List\r
     Str = ''\r
@@ -730,7 +801,7 @@ def GetHelpTextList(HelpTextClassList):
 \r
 def StringToArray(String):\r
     if isinstance(String, unicode):\r
-        if len(unicode) ==0:\r
+        if len(unicode) == 0:\r
             return "{0x00, 0x00}"\r
         return "{%s, 0x00, 0x00}" % ", ".join(["0x%02x, 0x00" % ord(C) for C in String])\r
     elif String.startswith('L"'):\r
@@ -755,7 +826,7 @@ def StringArrayLength(String):
         return (len(String) - 2 + 1)\r
     else:\r
         return len(String.split()) + 1\r
-    \r
+\r
 def RemoveDupOption(OptionString, Which="/I", Against=None):\r
     OptionList = OptionString.split()\r
     ValueList = []\r