Changed the uses of EdkLogger
[people/mcb30/basetools.git] / Source / Python / Common / String.py
1 # Copyright (c) 2007, Intel Corporation\r
2 # All rights reserved. This program and the accompanying materials\r
3 # are licensed and made available under the terms and conditions of the BSD License\r
4 # which accompanies this distribution.    The full text of the license may be found at\r
5 # http://opensource.org/licenses/bsd-license.php\r
6 #\r
7 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
8 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
9 \r
10 #\r
11 #This file is used to define some common useful string functions\r
12 #\r
13 \r
14 import DataType\r
15 import os.path\r
16 import string\r
17 import EdkLogger\r
18 from BuildToolError import *\r
19 \r
20 #\r
21 # Get a value list from a string with multiple values splited with SplitTag\r
22 # The default SplitTag is DataType.TAB_VALUE_SPLIT\r
23 # 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']\r
24 #\r
25 def GetSplitValueList(String, SplitTag = DataType.TAB_VALUE_SPLIT, MaxSplit = -1):\r
26     return map(lambda l: l.strip(), String.split(SplitTag, MaxSplit))\r
27 \r
28 #\r
29 # Find a key's all arches in dict, add the new arch to the list\r
30 # If not exist any arch, set the arch directly\r
31 #\r
32 def MergeArches(Dict, Key, Arch):\r
33     if Key in Dict.keys():\r
34         Dict[Key].append(Arch)\r
35     else:\r
36         Dict[Key] = Arch.split()\r
37 \r
38 #\r
39 # Parse a string with format "DEFINE <VarName> = <PATH>"\r
40 # Generate a map Defines[VarName] = PATH\r
41 # Return False if invalid format\r
42 #\r
43 def GenDefines(String, Arch, Defines):\r
44     if String.find(DataType.TAB_DEFINE + ' ') > -1:\r
45         List = String.replace(DataType.TAB_DEFINE + ' ', '').split(DataType.TAB_EQUAL_SPLIT)\r
46         if len(List) == 2:\r
47             Defines[(CleanString(List[0]), Arch)] = CleanString(List[1])\r
48             return 0\r
49         else:\r
50             return -1\r
51 \r
52     return 1\r
53 \r
54 #\r
55 # Parse a string with format "!include <Filename>"\r
56 # Return the file path\r
57 # Return False if invalid format or NOT FOUND\r
58 #\r
59 def GenInclude(String, IncludeFiles, Arch):\r
60     if String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1:\r
61         IncludeFile = CleanString(String[String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') + len(DataType.TAB_INCLUDE + ' ') : ])\r
62         MergeArches(IncludeFiles, IncludeFile, Arch)\r
63         return True\r
64     else:\r
65         return False\r
66 \r
67 #\r
68 # Parse a string with format "InfFilename [EXEC = ExecFilename]"\r
69 # Return (InfFilename, ExecFilename)\r
70 #\r
71 def GetExec(String):\r
72     InfFilename = ''\r
73     ExecFilename = ''\r
74     if String.find('EXEC') > -1:\r
75         InfFilename = String[ : String.find('EXEC')].strip()\r
76         ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip()\r
77     else:\r
78         InfFilename = String.strip()\r
79 \r
80     return (InfFilename, ExecFilename)\r
81 \r
82 #\r
83 # Parse a string with format "[<Family>:]<ToolFlag>=Flag"\r
84 # Return (Family, ToolFlag, Flag)\r
85 #\r
86 def GetBuildOption(String, File):\r
87     if String.find(DataType.TAB_EQUAL_SPLIT) < 0:\r
88         RaiseParserError(String, 'BuildOptions', File, '[<Family>:]<ToolFlag>=Flag')\r
89     (Family, ToolChain, Flag) = ('', '', '')\r
90     List = GetSplitValueList(String, DataType.TAB_EQUAL_SPLIT, MaxSplit = 1)\r
91     if List[0].find(':') > -1:\r
92         Family = CleanString(List[0][ : List[0].find(':')])\r
93         ToolChain = CleanString(List[0][List[0].find(':') + 1 : ])\r
94     else:\r
95         ToolChain = CleanString(List[0])\r
96     Flag = CleanString(List[1])\r
97 \r
98     return (Family, ToolChain, Flag)\r
99 \r
100 #\r
101 # Parse block of the components defined in dsc file\r
102 # Return KeyValues [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]\r
103 #\r
104 def GetComponents(Lines, Key, KeyValues, CommentCharacter):\r
105     #KeyValues [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]\r
106     if Lines.find(DataType.TAB_SECTION_END) > -1:\r
107         Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
108     (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)\r
109     ListItem = None\r
110     LibraryClassItem = []\r
111     BuildOption = []\r
112     Pcd = []\r
113 \r
114     LineList = Lines.split('\n')\r
115     for Line in LineList:\r
116         Line = CleanString(Line, CommentCharacter)\r
117         if Line == None or Line == '':\r
118             continue\r
119 \r
120         if findBlock == False:\r
121             ListItem = Line\r
122             #find '{' at line tail\r
123             if Line.endswith('{'):\r
124                 findBlock = True\r
125                 ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter)\r
126 \r
127         if findBlock:\r
128             if Line.find('<LibraryClasses>') != -1:\r
129                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False)\r
130                 continue\r
131             if Line.find('<BuildOptions>') != -1:\r
132                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False)\r
133                 continue\r
134             if Line.find('<PcdsFeatureFlag>') != -1:\r
135                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False)\r
136                 continue\r
137             if Line.find('<PcdsPatchableInModule>') != -1:\r
138                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False)\r
139                 continue\r
140             if Line.find('<PcdsFixedAtBuild>') != -1:\r
141                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False)\r
142                 continue\r
143             if Line.find('<PcdsDynamic>') != -1:\r
144                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False)\r
145                 continue\r
146             if Line.find('<PcdsDynamicEx>') != -1:\r
147                 (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True)\r
148                 continue\r
149             if Line.endswith('}'):\r
150                 #find '}' at line tail\r
151                 KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd])\r
152                 findBlock = False\r
153                 findLibraryClass = False\r
154                 findBuildOption = False\r
155                 findPcdsFeatureFlag = False\r
156                 findPcdsPatchableInModule = False\r
157                 findPcdsFixedAtBuild = False\r
158                 findPcdsDynamic = False\r
159                 findPcdsDynamicEx = False\r
160                 LibraryClassItem = []\r
161                 BuildOption = []\r
162                 Pcd = []\r
163                 continue\r
164 \r
165         if findBlock:\r
166             if findLibraryClass:\r
167                 LibraryClassItem.append(Line)\r
168             elif findBuildOption:\r
169                 BuildOption.append(Line)\r
170             elif findPcdsFeatureFlag:\r
171                 Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line))\r
172             elif findPcdsPatchableInModule:\r
173                 Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line))\r
174             elif findPcdsFixedAtBuild:\r
175                 Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line))\r
176             elif findPcdsDynamic:\r
177                 Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line))\r
178             elif findPcdsDynamicEx:\r
179                 Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line))\r
180         else:\r
181             KeyValues.append([ListItem, [], [], []])\r
182 \r
183     return True\r
184 \r
185 #\r
186 # Get Library Class definition when no module type defined\r
187 #\r
188 def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter):\r
189     newKey = SplitModuleType(Key)\r
190     Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
191     LineList = Lines.splitlines()\r
192     for Line in LineList:\r
193         Line = CleanString(Line, CommentCharacter)\r
194         if Line != '' and Line[0] != CommentCharacter:\r
195             KeyValues.append([CleanString(Line, CommentCharacter), newKey[1]])\r
196 \r
197     return True\r
198 \r
199 #\r
200 # Get Dynamic Pcds\r
201 #\r
202 def GetDynamics(Lines, Key, KeyValues, CommentCharacter):\r
203     #\r
204     # Get SkuId Name List\r
205     #\r
206     SkuIdNameList = SplitModuleType(Key)\r
207 \r
208     Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
209     LineList = Lines.splitlines()\r
210     for Line in LineList:\r
211         Line = CleanString(Line, CommentCharacter)\r
212         if Line != '' and Line[0] != CommentCharacter:\r
213             KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]])\r
214 \r
215     return True\r
216 \r
217 #\r
218 # Split ModuleType out of section defien to get key\r
219 # [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [ 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ]\r
220 #\r
221 def SplitModuleType(Key):\r
222     KeyList = Key.split(DataType.TAB_SPLIT)\r
223     KeyList.append('')                    # Fill in for arch\r
224     KeyList.append('')                    # Fill in for moduletype\r
225     ReturnValue = []\r
226     KeyValue = KeyList[0]\r
227     if KeyList[1] != '':\r
228         KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1]\r
229     ReturnValue.append(KeyValue)\r
230     ReturnValue.append(GetSplitValueList(KeyList[2]))\r
231 \r
232     return ReturnValue\r
233 \r
234 #\r
235 # Create a normal path\r
236 # And replace DFEINE in the path\r
237 #\r
238 def NormPath(Path, Defines = {}):\r
239     if Path != '':\r
240         # Replace with Define\r
241         for Key in Defines.keys():\r
242             Path = Path.replace(Key, Defines[Key])\r
243 \r
244         # Remove ${WORKSPACE}\r
245         Path = Path.replace(DataType.TAB_WORKSPACE, '')\r
246 \r
247         # To local path format\r
248         Path = os.path.normpath(Path)\r
249         if Path[0] == os.path.sep:\r
250             Path = Path[1:]\r
251 \r
252     return Path\r
253 \r
254 #\r
255 # Remove comments in a string\r
256 # Remove spaces\r
257 #\r
258 def CleanString(Line, CommentCharacter = DataType.TAB_COMMENT_SPLIT):\r
259     #remove whitespace\r
260     Line = Line.strip();\r
261     #remove comments\r
262     Line = Line.split(CommentCharacter, 1)[0];\r
263     #remove whitespace again\r
264     Line = Line.strip();\r
265 \r
266     return Line\r
267 \r
268 def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter):\r
269     Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
270     LineList = Lines.split('\n')\r
271     for Line in LineList:\r
272         Line = CleanString(Line, CommentCharacter)\r
273         if Line != '' and Line[0] != CommentCharacter:\r
274             KeyValues += [Line]\r
275 \r
276     return True\r
277 \r
278 def GetDefineValue(String, Key, CommentCharacter):\r
279     String = CleanString(String)\r
280     return String[String.find(Key + ' ') + len(Key + ' ') : ]\r
281 \r
282 def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter):\r
283     Lines = Lines.split('\n')\r
284     Keys = []\r
285     Value = ''\r
286     DefineValues = ['']\r
287     SpecValues = ['']\r
288 \r
289     for Line in Lines:\r
290         #\r
291         # Handle DEFINE and SPEC\r
292         #\r
293         if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1:\r
294             if '' in DefineValues:\r
295                 DefineValues.remove('')\r
296             DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter))\r
297             continue\r
298         if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1:\r
299             if '' in SpecValues:\r
300                 SpecValues.remove('')\r
301             SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter))\r
302             continue\r
303 \r
304         #\r
305         # Handle Others\r
306         #\r
307         LineList = Line.split(KeySplitCharacter, 1)\r
308         if len(LineList) >= 2:\r
309             Key = LineList[0].split()\r
310             if len(Key) == 1 and Key[0][0] != CommentCharacter:\r
311                 #Remove comments and white spaces\r
312                 LineList[1] = CleanString(LineList[1], CommentCharacter)\r
313                 if ValueSplitFlag:\r
314                     Value = map(string.strip, LineList[1].split(ValueSplitCharacter))\r
315                 else:\r
316                     Value = CleanString(LineList[1], CommentCharacter).splitlines()\r
317 \r
318                 if Key[0] not in Keys:\r
319                     Dictionary[Key[0]] = Value\r
320                     Keys.append(Key[0])\r
321                 else:\r
322                     Dictionary[Key[0]].extend(Value)\r
323 \r
324     if DefineValues == []:\r
325         DefineValues == ['']\r
326     if SpecValues == []:\r
327         SpecValues == ['']\r
328     Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues\r
329     Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues\r
330 \r
331     return True\r
332 \r
333 #\r
334 # Do pre-check for a file before it is parsed\r
335 # Check $()\r
336 # Check []\r
337 #\r
338 def PreCheck(FileName, FileContent, SupSectionTag):\r
339     LineNo = 0\r
340     IsFailed = False\r
341     for Line in FileContent.splitlines():\r
342         LineNo = LineNo + 1\r
343         Line = CleanString(Line)\r
344         #\r
345         # Check $()\r
346         #\r
347         if Line.find('$') > -1:\r
348             if Line.find('$(') < 0 or Line.find(')') < 0:\r
349                 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName)\r
350 \r
351         #\r
352         # Check []\r
353         #\r
354         if Line.find('[') > -1 or Line.find(']') > -1:\r
355             #\r
356             # Only get one '[' or one ']'\r
357             #\r
358             if not (Line.find('[') > -1 and Line.find(']') > -1):\r
359                 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName)\r
360 \r
361             #\r
362             # Tag not in defined value\r
363             #\r
364             TagList = GetSplitValueList(Line, DataType.TAB_COMMA_SPLIT)\r
365             for Tag in TagList:\r
366                 Tag = Tag.split(DataType.TAB_SPLIT, 1)[0].replace('[', '').replace(']', '').strip()\r
367                 if Tag.upper() == DataType.TAB_COMMON_DEFINES.upper():\r
368                     break\r
369                 if Tag.upper() == DataType.TAB_USER_EXTENSIONS.upper():\r
370                     break\r
371                 if Tag.upper() not in map(lambda s: s.upper(), SupSectionTag):\r
372                     ErrorMsg = "'%s' is not a supportted section name." % Tag\r
373                     EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=FileName, Line=LineNo)\r
374 \r
375     if IsFailed:\r
376        EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName)\r
377 \r
378 #\r
379 # Check if the Filename is including ExtName\r
380 # Pass if it exists\r
381 # Raise a error message if it not exists\r
382 #\r
383 def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line):\r
384     if CheckFilename != '' and CheckFilename != None:\r
385         (Root, Ext) = os.path.splitext(CheckFilename)\r
386         if Ext.upper() != ExtName.upper():\r
387             ContainerFile = open(ContainerFilename, 'r').read()\r
388             LineNo = GetLineNo(ContainerFile, Line)\r
389             ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName)\r
390             EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo,\r
391                             File=ContainerFilename)\r
392 \r
393     return True\r
394 \r
395 #\r
396 # Check if the file exists\r
397 # Pass if it exists\r
398 # Raise a error message if it not exists\r
399 #\r
400 def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line):\r
401     if CheckFilename != '' and CheckFilename != None:\r
402         CheckFile = WorkspaceFile(WorkspaceDir, NormPath(CheckFilename))\r
403         if os.path.exists(CheckFile) and os.path.isfile(CheckFile):\r
404             pass\r
405         else:\r
406             ContainerFile = open(ContainerFilename, 'r').read()\r
407             LineNo = GetLineNo(ContainerFile, Line)\r
408             ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName)\r
409             EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg,\r
410                             File=ContainerFilename, Line=LineNo)\r
411 \r
412     return True\r
413 \r
414 #\r
415 # Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>\r
416 #\r
417 def CheckPcdTokenInfo(TokenInfoString, Section, File):\r
418     if TokenInfoString != '' and TokenInfoString != None:\r
419         Format = '<TokenSpaceGuidCName>.<PcdCName>'\r
420         TokenInfoList = GetSplitValueList(TokenInfoString, DataType.TAB_SPLIT)\r
421         if len(TokenInfoList) != 2:\r
422             RaiseParserError(TokenInfoString, Section, File, Format)\r
423 \r
424     return True\r
425 \r
426 #\r
427 # Find the index of a line in a file\r
428 #\r
429 def GetLineNo(FileContent, Line):\r
430     LineList = FileContent.splitlines()\r
431     for Index in range(len(LineList)):\r
432         if LineList[Index].find(Line) > -1:\r
433             return Index + 1\r
434 \r
435     return -1\r
436 \r
437 #\r
438 # Raise a parser error\r
439 #\r
440 def RaiseParserError(Line, Section, File, Format):\r
441     LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line)\r
442     ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section)\r
443     EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo,\r
444                     ExtraData="Correct format is " + Format)\r
445 \r
446 #\r
447 # Return a full path with workspace dir\r
448 #\r
449 def WorkspaceFile(WorkspaceDir, Filename):\r
450     return os.path.join(NormPath(WorkspaceDir), NormPath(Filename))\r
451 \r
452 if __name__ == '__main__':\r
453     print SplitModuleType('LibraryClasses.common.DXE_RUNTIME_DRIVER')\r
454     print SplitModuleType('Library.common')\r
455     print SplitModuleType('Librarsdsfwe')\r
456     print NormPath('sdfas//dsfsadf//dsfsd')\r
457     print NormPath('\\dsfsdf\\\\sd\\fsd\\dsfsdfsdf\\\\')\r