]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/Python/Common/String.py
Sync BaseTools Trunk (version r2387) to EDKII main trunk.
[mirror_edk2.git] / BaseTools / Source / Python / Common / String.py
index 1f199fe2ca58ff832185dfea8b4efb342b4a16c7..a35f728dc0151c0ade819c93ffc4606ab019260d 100644 (file)
@@ -20,8 +20,12 @@ 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
+gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')\r
 \r
 ## GetSplitValueList\r
 #\r
@@ -36,7 +40,52 @@ from BuildToolError import *
 # @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
+    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
@@ -207,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
@@ -274,14 +325,40 @@ def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSty
     #\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\r
+    # remove comments, but we should escape comment character in string\r
     #\r
-    Line = Line.split(CommentCharacter, 1)[0];\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 InString :\r
+            CommentInString = True\r
+        elif Line[Index] == CommentCharacter and not InString :\r
+            Line = Line[0: Index]\r
+            break\r
+        \r
+    if CommentInString:\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
@@ -289,6 +366,50 @@ def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppSty
 \r
     return Line\r
 \r
+## CleanString2\r
+#\r
+# Split comments in a string\r
+# Remove spaces\r
+#\r
+# @param Line:              The string to be cleaned\r
+# @param CommentCharacter:  Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT\r
+#\r
+# @retval Path Formatted path\r
+#\r
+def CleanString2(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):\r
+    #\r
+    # remove whitespace\r
+    #\r
+    Line = Line.strip();\r
+    #\r
+    # Replace Edk's comment character\r
+    #\r
+    if AllowCppStyleComment:\r
+        Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)\r
+    #\r
+    # separate comments and statements\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
+        # Remove prefixed and trailing comment characters\r
+        Start = 0\r
+        End = len(Comment)\r
+        while Start < End and Comment.startswith(CommentCharacter, Start, End):\r
+            Start += 1\r
+        while End >= 0 and Comment.endswith(CommentCharacter, Start, End):\r
+            End -= 1\r
+        Comment = Comment[Start:End]\r
+        Comment = Comment.strip()\r
+    else:\r
+        Comment = ''\r
+\r
+    return Line, Comment\r
+\r
 ## GetMultipleValuesOfKeyFromLines\r
 #\r
 # Parse multiple strings to clean comment and spaces\r
@@ -326,6 +447,34 @@ def GetDefineValue(String, Key, CommentCharacter):
     String = CleanString(String)\r
     return String[String.find(Key + ' ') + len(Key + ' ') : ]\r
 \r
+## GetHexVerValue\r
+#\r
+# Get a Hex Version Value\r
+#\r
+# @param VerString:         The version string to be parsed\r
+#\r
+#\r
+# @retval:      If VerString is incorrectly formatted, return "None" which will break the build.\r
+#               If VerString is correctly formatted, return a Hex value of the Version Number (0xmmmmnnnn)\r
+#                   where mmmm is the major number and nnnn is the adjusted minor number.\r
+#\r
+def GetHexVerValue(VerString):\r
+    VerString = CleanString(VerString)\r
+\r
+    if gHumanReadableVerPatt.match(VerString):\r
+        ValueList = VerString.split('.')\r
+        Major = ValueList[0]\r
+        Minor = ValueList[1]\r
+        if len(Minor) == 1:\r
+            Minor += '0'\r
+        DeciValue = (int(Major) << 16) + int(Minor);\r
+        return "0x%08x"%DeciValue\r
+    elif gHexVerPatt.match(VerString):\r
+        return VerString\r
+    else:\r
+        return None\r
+\r
+\r
 ## GetSingleValueOfKeyFromLines\r
 #\r
 # Parse multiple strings as below to get value of each definition line\r
@@ -607,11 +756,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 = GetSplitValueList(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 + GetSplitValueList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1]\r
             ReservedLine = ''\r
             IsFindBlockComment = False\r
         if IsFindBlockComment:\r