]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/UPT/Library/StringUtils.py
BaseTools: Adjust the spaces around commas and colons
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / StringUtils.py
CommitLineData
4234283c 1## @file\r
421ccda3 2# This file is used to define common string related functions used in parsing\r
4234283c
LG
3# process\r
4#\r
64285f15 5# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
4234283c 6#\r
421ccda3
HC
7# This program and the accompanying materials are licensed and made available\r
8# under the terms and conditions of the BSD License which accompanies this\r
9# distribution. The full text of the license may be found at\r
4234283c
LG
10# http://opensource.org/licenses/bsd-license.php\r
11#\r
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14#\r
15'''\r
64285f15 16StringUtils\r
4234283c
LG
17'''\r
18##\r
19# Import Modules\r
20#\r
21import re\r
22import os.path\r
23from string import strip\r
24import Logger.Log as Logger\r
25import Library.DataType as DataType\r
26from Logger.ToolError import FORMAT_INVALID\r
27from Logger.ToolError import PARSER_ERROR\r
28from Logger import StringTable as ST\r
29\r
30#\r
31# Regular expression for matching macro used in DSC/DEC/INF file inclusion\r
32#\r
33gMACRO_PATTERN = re.compile("\$\(([_A-Z][_A-Z0-9]*)\)", re.UNICODE)\r
34\r
35## GetSplitValueList\r
36#\r
37# Get a value list from a string with multiple values splited with SplitTag\r
38# The default SplitTag is DataType.TAB_VALUE_SPLIT\r
39# 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']\r
40#\r
41# @param String: The input string to be splitted\r
42# @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT\r
43# @param MaxSplit: The max number of split values, default is -1\r
44#\r
45#\r
421ccda3 46def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):\r
4234283c
LG
47 return map(lambda l: l.strip(), String.split(SplitTag, MaxSplit))\r
48\r
49## MergeArches\r
50#\r
51# Find a key's all arches in dict, add the new arch to the list\r
52# If not exist any arch, set the arch directly\r
53#\r
54# @param Dict: The input value for Dict\r
55# @param Key: The input value for Key\r
56# @param Arch: The Arch to be added or merged\r
57#\r
58def MergeArches(Dict, Key, Arch):\r
59 if Key in Dict.keys():\r
60 Dict[Key].append(Arch)\r
61 else:\r
62 Dict[Key] = Arch.split()\r
63\r
64## GenDefines\r
65#\r
66# Parse a string with format "DEFINE <VarName> = <PATH>"\r
67# Generate a map Defines[VarName] = PATH\r
68# Return False if invalid format\r
69#\r
70# @param String: String with DEFINE statement\r
71# @param Arch: Supportted Arch\r
72# @param Defines: DEFINE statement to be parsed\r
73#\r
74def GenDefines(String, Arch, Defines):\r
75 if String.find(DataType.TAB_DEFINE + ' ') > -1:\r
76 List = String.replace(DataType.TAB_DEFINE + ' ', '').\\r
77 split(DataType.TAB_EQUAL_SPLIT)\r
78 if len(List) == 2:\r
79 Defines[(CleanString(List[0]), Arch)] = CleanString(List[1])\r
80 return 0\r
81 else:\r
82 return -1\r
83 return 1\r
84\r
85## GetLibraryClassesWithModuleType\r
86#\r
87# Get Library Class definition when no module type defined\r
88#\r
89# @param Lines: The content to be parsed\r
90# @param Key: Reserved\r
91# @param KeyValues: To store data after parsing\r
92# @param CommentCharacter: Comment char, used to ignore comment content\r
93#\r
94def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter):\r
95 NewKey = SplitModuleType(Key)\r
96 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
97 LineList = Lines.splitlines()\r
98 for Line in LineList:\r
99 Line = CleanString(Line, CommentCharacter)\r
100 if Line != '' and Line[0] != CommentCharacter:\r
101 KeyValues.append([CleanString(Line, CommentCharacter), NewKey[1]])\r
102\r
103 return True\r
104\r
105## GetDynamics\r
106#\r
107# Get Dynamic Pcds\r
108#\r
109# @param Lines: The content to be parsed\r
110# @param Key: Reserved\r
111# @param KeyValues: To store data after parsing\r
112# @param CommentCharacter: Comment char, used to ignore comment content\r
113#\r
114def GetDynamics(Lines, Key, KeyValues, CommentCharacter):\r
115 #\r
116 # Get SkuId Name List\r
117 #\r
118 SkuIdNameList = SplitModuleType(Key)\r
119\r
120 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
121 LineList = Lines.splitlines()\r
122 for Line in LineList:\r
123 Line = CleanString(Line, CommentCharacter)\r
124 if Line != '' and Line[0] != CommentCharacter:\r
125 KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]])\r
126\r
127 return True\r
128\r
129## SplitModuleType\r
130#\r
131# Split ModuleType out of section defien to get key\r
421ccda3 132# [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [\r
4234283c
LG
133# 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ]\r
134#\r
135# @param Key: String to be parsed\r
136#\r
137def SplitModuleType(Key):\r
138 KeyList = Key.split(DataType.TAB_SPLIT)\r
139 #\r
140 # Fill in for arch\r
141 #\r
142 KeyList.append('')\r
143 #\r
144 # Fill in for moduletype\r
145 #\r
146 KeyList.append('')\r
147 ReturnValue = []\r
148 KeyValue = KeyList[0]\r
149 if KeyList[1] != '':\r
150 KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1]\r
151 ReturnValue.append(KeyValue)\r
152 ReturnValue.append(GetSplitValueList(KeyList[2]))\r
153\r
154 return ReturnValue\r
155\r
156## Replace macro in string\r
157#\r
158# This method replace macros used in given string. The macros are given in a\r
159# dictionary.\r
160#\r
161# @param String String to be processed\r
162# @param MacroDefinitions The macro definitions in the form of dictionary\r
163# @param SelfReplacement To decide whether replace un-defined macro to ''\r
164# @param Line: The content contain line string and line number\r
165# @param FileName: The meta-file file name\r
166#\r
421ccda3 167def ReplaceMacro(String, MacroDefinitions=None, SelfReplacement=False, Line=None, FileName=None, Flag=False):\r
4234283c 168 LastString = String\r
4231a819 169 if MacroDefinitions is None:\r
4234283c
LG
170 MacroDefinitions = {}\r
171 while MacroDefinitions:\r
172 QuotedStringList = []\r
173 HaveQuotedMacroFlag = False\r
174 if not Flag:\r
175 MacroUsed = gMACRO_PATTERN.findall(String)\r
176 else:\r
177 ReQuotedString = re.compile('\"')\r
178 QuotedStringList = ReQuotedString.split(String)\r
179 if len(QuotedStringList) >= 3:\r
180 HaveQuotedMacroFlag = True\r
181 Count = 0\r
182 MacroString = ""\r
183 for QuotedStringItem in QuotedStringList:\r
184 Count += 1\r
185 if Count % 2 != 0:\r
186 MacroString += QuotedStringItem\r
421ccda3
HC
187\r
188 if Count == len(QuotedStringList) and Count % 2 == 0:\r
4234283c 189 MacroString += QuotedStringItem\r
421ccda3 190\r
4234283c
LG
191 MacroUsed = gMACRO_PATTERN.findall(MacroString)\r
192 #\r
193 # no macro found in String, stop replacing\r
194 #\r
195 if len(MacroUsed) == 0:\r
196 break\r
197 for Macro in MacroUsed:\r
198 if Macro not in MacroDefinitions:\r
199 if SelfReplacement:\r
200 String = String.replace("$(%s)" % Macro, '')\r
421ccda3 201 Logger.Debug(5, "Delete undefined MACROs in file %s line %d: %s!" % (FileName, Line[1], Line[0]))\r
4234283c
LG
202 continue\r
203 if not HaveQuotedMacroFlag:\r
204 String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro])\r
205 else:\r
206 Count = 0\r
207 for QuotedStringItem in QuotedStringList:\r
208 Count += 1\r
209 if Count % 2 != 0:\r
421ccda3 210 QuotedStringList[Count - 1] = QuotedStringList[Count - 1].replace("$(%s)" % Macro,\r
4234283c 211 MacroDefinitions[Macro])\r
421ccda3
HC
212 elif Count == len(QuotedStringList) and Count % 2 == 0:\r
213 QuotedStringList[Count - 1] = QuotedStringList[Count - 1].replace("$(%s)" % Macro,\r
4234283c 214 MacroDefinitions[Macro])\r
421ccda3 215\r
4234283c
LG
216 RetString = ''\r
217 if HaveQuotedMacroFlag:\r
218 Count = 0\r
219 for QuotedStringItem in QuotedStringList:\r
421ccda3 220 Count += 1\r
4234283c 221 if Count != len(QuotedStringList):\r
421ccda3 222 RetString += QuotedStringList[Count - 1] + "\""\r
4234283c 223 else:\r
421ccda3
HC
224 RetString += QuotedStringList[Count - 1]\r
225\r
4234283c 226 String = RetString\r
421ccda3
HC
227\r
228 #\r
4234283c
LG
229 # in case there's macro not defined\r
230 #\r
231 if String == LastString:\r
232 break\r
233 LastString = String\r
234\r
235 return String\r
236\r
237## NormPath\r
238#\r
239# Create a normal path\r
240# And replace DFEINE in the path\r
241#\r
242# @param Path: The input value for Path to be converted\r
243# @param Defines: A set for DEFINE statement\r
244#\r
421ccda3 245def NormPath(Path, Defines=None):\r
4234283c 246 IsRelativePath = False\r
4231a819 247 if Defines is None:\r
4234283c
LG
248 Defines = {}\r
249 if Path:\r
250 if Path[0] == '.':\r
251 IsRelativePath = True\r
252 #\r
253 # Replace with Define\r
254 #\r
255 if Defines:\r
256 Path = ReplaceMacro(Path, Defines)\r
257 #\r
258 # To local path format\r
259 #\r
260 Path = os.path.normpath(Path)\r
261\r
262 if IsRelativePath and Path[0] != '.':\r
263 Path = os.path.join('.', Path)\r
264 return Path\r
265\r
266## CleanString\r
267#\r
268# Remove comments in a string\r
269# Remove spaces\r
270#\r
271# @param Line: The string to be cleaned\r
421ccda3 272# @param CommentCharacter: Comment char, used to ignore comment content,\r
4234283c
LG
273# default is DataType.TAB_COMMENT_SPLIT\r
274#\r
275def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):\r
276 #\r
277 # remove whitespace\r
278 #\r
279 Line = Line.strip()\r
280 #\r
281 # Replace EDK1's comment character\r
282 #\r
283 if AllowCppStyleComment:\r
284 Line = Line.replace(DataType.TAB_COMMENT_EDK1_SPLIT, CommentCharacter)\r
285 #\r
286 # remove comments, but we should escape comment character in string\r
287 #\r
288 InString = False\r
289 for Index in range(0, len(Line)):\r
290 if Line[Index] == '"':\r
291 InString = not InString\r
292 elif Line[Index] == CommentCharacter and not InString:\r
293 Line = Line[0: Index]\r
294 break\r
295 #\r
296 # remove whitespace again\r
297 #\r
298 Line = Line.strip()\r
299\r
300 return Line\r
301\r
302## CleanString2\r
303#\r
304# Split comments in a string\r
305# Remove spaces\r
306#\r
307# @param Line: The string to be cleaned\r
421ccda3 308# @param CommentCharacter: Comment char, used to ignore comment content,\r
4234283c
LG
309# default is DataType.TAB_COMMENT_SPLIT\r
310#\r
311def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):\r
312 #\r
313 # remove whitespace\r
314 #\r
315 Line = Line.strip()\r
316 #\r
317 # Replace EDK1's comment character\r
318 #\r
319 if AllowCppStyleComment:\r
320 Line = Line.replace(DataType.TAB_COMMENT_EDK1_SPLIT, CommentCharacter)\r
321 #\r
322 # separate comments and statements\r
323 #\r
324 LineParts = Line.split(CommentCharacter, 1)\r
325 #\r
326 # remove whitespace again\r
327 #\r
328 Line = LineParts[0].strip()\r
329 if len(LineParts) > 1:\r
330 Comment = LineParts[1].strip()\r
331 #\r
332 # Remove prefixed and trailing comment characters\r
333 #\r
334 Start = 0\r
335 End = len(Comment)\r
336 while Start < End and Comment.startswith(CommentCharacter, Start, End):\r
337 Start += 1\r
338 while End >= 0 and Comment.endswith(CommentCharacter, Start, End):\r
339 End -= 1\r
340 Comment = Comment[Start:End]\r
341 Comment = Comment.strip()\r
342 else:\r
343 Comment = ''\r
344\r
345 return Line, Comment\r
346\r
347## GetMultipleValuesOfKeyFromLines\r
348#\r
349# Parse multiple strings to clean comment and spaces\r
350# The result is saved to KeyValues\r
351#\r
352# @param Lines: The content to be parsed\r
353# @param Key: Reserved\r
354# @param KeyValues: To store data after parsing\r
355# @param CommentCharacter: Comment char, used to ignore comment content\r
356#\r
357def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter):\r
358 if Key:\r
359 pass\r
360 if KeyValues:\r
361 pass\r
362 Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]\r
363 LineList = Lines.split('\n')\r
364 for Line in LineList:\r
365 Line = CleanString(Line, CommentCharacter)\r
366 if Line != '' and Line[0] != CommentCharacter:\r
367 KeyValues += [Line]\r
368 return True\r
369\r
370## GetDefineValue\r
371#\r
372# Parse a DEFINE statement to get defined value\r
373# DEFINE Key Value\r
374#\r
375# @param String: The content to be parsed\r
376# @param Key: The key of DEFINE statement\r
377# @param CommentCharacter: Comment char, used to ignore comment content\r
378#\r
379def GetDefineValue(String, Key, CommentCharacter):\r
380 if CommentCharacter:\r
381 pass\r
382 String = CleanString(String)\r
383 return String[String.find(Key + ' ') + len(Key + ' ') : ]\r
384\r
385## GetSingleValueOfKeyFromLines\r
386#\r
387# Parse multiple strings as below to get value of each definition line\r
388# Key1 = Value1\r
389# Key2 = Value2\r
390# The result is saved to Dictionary\r
391#\r
392# @param Lines: The content to be parsed\r
393# @param Dictionary: To store data after parsing\r
394# @param CommentCharacter: Comment char, be used to ignore comment content\r
395# @param KeySplitCharacter: Key split char, between key name and key value.\r
396# Key1 = Value1, '=' is the key split char\r
421ccda3 397# @param ValueSplitFlag: Value split flag, be used to decide if has\r
4234283c 398# multiple values\r
421ccda3
HC
399# @param ValueSplitCharacter: Value split char, be used to split multiple\r
400# values. Key1 = Value1|Value2, '|' is the value\r
4234283c
LG
401# split char\r
402#\r
403def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, \\r
404 ValueSplitFlag, ValueSplitCharacter):\r
405 Lines = Lines.split('\n')\r
406 Keys = []\r
407 Value = ''\r
408 DefineValues = ['']\r
409 SpecValues = ['']\r
410\r
411 for Line in Lines:\r
412 #\r
413 # Handle DEFINE and SPEC\r
414 #\r
415 if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1:\r
416 if '' in DefineValues:\r
417 DefineValues.remove('')\r
418 DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter))\r
419 continue\r
420 if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1:\r
421 if '' in SpecValues:\r
422 SpecValues.remove('')\r
423 SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter))\r
424 continue\r
425\r
426 #\r
427 # Handle Others\r
428 #\r
429 LineList = Line.split(KeySplitCharacter, 1)\r
430 if len(LineList) >= 2:\r
431 Key = LineList[0].split()\r
432 if len(Key) == 1 and Key[0][0] != CommentCharacter:\r
433 #\r
434 # Remove comments and white spaces\r
435 #\r
436 LineList[1] = CleanString(LineList[1], CommentCharacter)\r
437 if ValueSplitFlag:\r
438 Value = map(strip, LineList[1].split(ValueSplitCharacter))\r
439 else:\r
440 Value = CleanString(LineList[1], CommentCharacter).splitlines()\r
441\r
442 if Key[0] in Dictionary:\r
443 if Key[0] not in Keys:\r
444 Dictionary[Key[0]] = Value\r
445 Keys.append(Key[0])\r
446 else:\r
447 Dictionary[Key[0]].extend(Value)\r
448 else:\r
449 Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0]\r
450\r
451 if DefineValues == []:\r
452 DefineValues = ['']\r
453 if SpecValues == []:\r
454 SpecValues = ['']\r
455 Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues\r
456 Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues\r
457\r
458 return True\r
459\r
460## The content to be parsed\r
461#\r
462# Do pre-check for a file before it is parsed\r
463# Check $()\r
464# Check []\r
465#\r
466# @param FileName: Used for error report\r
467# @param FileContent: File content to be parsed\r
468# @param SupSectionTag: Used for error report\r
469#\r
470def PreCheck(FileName, FileContent, SupSectionTag):\r
471 if SupSectionTag:\r
472 pass\r
473 LineNo = 0\r
474 IsFailed = False\r
475 NewFileContent = ''\r
476 for Line in FileContent.splitlines():\r
477 LineNo = LineNo + 1\r
478 #\r
479 # Clean current line\r
480 #\r
481 Line = CleanString(Line)\r
482 #\r
483 # Remove commented line\r
484 #\r
485 if Line.find(DataType.TAB_COMMA_SPLIT) == 0:\r
486 Line = ''\r
487 #\r
488 # Check $()\r
489 #\r
490 if Line.find('$') > -1:\r
491 if Line.find('$(') < 0 or Line.find(')') < 0:\r
421ccda3 492 Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR)\r
4234283c
LG
493 #\r
494 # Check []\r
495 #\r
496 if Line.find('[') > -1 or Line.find(']') > -1:\r
497 #\r
498 # Only get one '[' or one ']'\r
499 #\r
500 if not (Line.find('[') > -1 and Line.find(']') > -1):\r
421ccda3 501 Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR)\r
4234283c
LG
502 #\r
503 # Regenerate FileContent\r
504 #\r
505 NewFileContent = NewFileContent + Line + '\r\n'\r
506\r
507 if IsFailed:\r
421ccda3 508 Logger.Error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=Logger.IS_RAISE_ERROR)\r
4234283c
LG
509\r
510 return NewFileContent\r
511\r
512## CheckFileType\r
513#\r
514# Check if the Filename is including ExtName\r
515# Return True if it exists\r
516# Raise a error message if it not exists\r
517#\r
518# @param CheckFilename: Name of the file to be checked\r
519# @param ExtName: Ext name of the file to be checked\r
520# @param ContainerFilename: The container file which describes the file to be\r
521# checked, used for error report\r
522# @param SectionName: Used for error report\r
523# @param Line: The line in container file which defines the file\r
524# to be checked\r
525#\r
421ccda3 526def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1):\r
4231a819 527 if CheckFilename != '' and CheckFilename is not None:\r
4234283c
LG
528 (Root, Ext) = os.path.splitext(CheckFilename)\r
529 if Ext.upper() != ExtName.upper() and Root:\r
530 ContainerFile = open(ContainerFilename, 'r').read()\r
531 if LineNo == -1:\r
532 LineNo = GetLineNo(ContainerFile, Line)\r
533 ErrorMsg = ST.ERR_SECTIONNAME_INVALID % (SectionName, CheckFilename, ExtName)\r
534 Logger.Error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo, \\r
535 File=ContainerFilename, RaiseError=Logger.IS_RAISE_ERROR)\r
536\r
537 return True\r
538\r
539## CheckFileExist\r
540#\r
541# Check if the file exists\r
542# Return True if it exists\r
543# Raise a error message if it not exists\r
544#\r
545# @param CheckFilename: Name of the file to be checked\r
546# @param WorkspaceDir: Current workspace dir\r
421ccda3 547# @param ContainerFilename: The container file which describes the file to\r
4234283c
LG
548# be checked, used for error report\r
549# @param SectionName: Used for error report\r
421ccda3 550# @param Line: The line in container file which defines the\r
4234283c
LG
551# file to be checked\r
552#\r
421ccda3 553def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1):\r
4234283c 554 CheckFile = ''\r
4231a819 555 if CheckFilename != '' and CheckFilename is not None:\r
4234283c
LG
556 CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename)\r
557 if not os.path.isfile(CheckFile):\r
558 ContainerFile = open(ContainerFilename, 'r').read()\r
559 if LineNo == -1:\r
560 LineNo = GetLineNo(ContainerFile, Line)\r
561 ErrorMsg = ST.ERR_CHECKFILE_NOTFOUND % (CheckFile, SectionName)\r
562 Logger.Error("Parser", PARSER_ERROR, ErrorMsg,\r
421ccda3 563 File=ContainerFilename, Line=LineNo, RaiseError=Logger.IS_RAISE_ERROR)\r
4234283c
LG
564 return CheckFile\r
565\r
566## GetLineNo\r
567#\r
568# Find the index of a line in a file\r
569#\r
570# @param FileContent: Search scope\r
571# @param Line: Search key\r
572#\r
573def GetLineNo(FileContent, Line, IsIgnoreComment=True):\r
574 LineList = FileContent.splitlines()\r
575 for Index in range(len(LineList)):\r
576 if LineList[Index].find(Line) > -1:\r
577 #\r
578 # Ignore statement in comment\r
579 #\r
580 if IsIgnoreComment:\r
581 if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT:\r
582 continue\r
583 return Index + 1\r
584\r
585 return -1\r
586\r
587## RaiseParserError\r
588#\r
589# Raise a parser error\r
590#\r
591# @param Line: String which has error\r
592# @param Section: Used for error report\r
593# @param File: File which has the string\r
594# @param Format: Correct format\r
595#\r
421ccda3 596def RaiseParserError(Line, Section, File, Format='', LineNo= -1):\r
4234283c
LG
597 if LineNo == -1:\r
598 LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line)\r
599 ErrorMsg = ST.ERR_INVALID_NOTFOUND % (Line, Section)\r
600 if Format != '':\r
601 Format = "Correct format is " + Format\r
602 Logger.Error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, \\r
603 ExtraData=Format, RaiseError=Logger.IS_RAISE_ERROR)\r
604\r
605## WorkspaceFile\r
606#\r
607# Return a full path with workspace dir\r
608#\r
609# @param WorkspaceDir: Workspace dir\r
610# @param Filename: Relative file name\r
611#\r
612def WorkspaceFile(WorkspaceDir, Filename):\r
613 return os.path.join(NormPath(WorkspaceDir), NormPath(Filename))\r
614\r
615## Split string\r
616#\r
617# Revmove '"' which startswith and endswith string\r
618#\r
619# @param String: The string need to be splited\r
620#\r
621def SplitString(String):\r
622 if String.startswith('\"'):\r
623 String = String[1:]\r
624 if String.endswith('\"'):\r
625 String = String[:-1]\r
626 return String\r
627\r
628## Convert To Sql String\r
629#\r
630# Replace "'" with "''" in each item of StringList\r
631#\r
632# @param StringList: A list for strings to be converted\r
633#\r
634def ConvertToSqlString(StringList):\r
ccaa7754 635 return map(lambda s: s.replace("'", "''"), StringList)\r
4234283c
LG
636\r
637## Convert To Sql String\r
638#\r
639# Replace "'" with "''" in the String\r
640#\r
641# @param String: A String to be converted\r
642#\r
643def ConvertToSqlString2(String):\r
644 return String.replace("'", "''")\r
645\r
4234283c
LG
646## GetStringOfList\r
647#\r
648# Get String of a List\r
649#\r
650# @param Lines: string list\r
651# @param Split: split character\r
652#\r
421ccda3 653def GetStringOfList(List, Split=' '):\r
4234283c
LG
654 if type(List) != type([]):\r
655 return List\r
656 Str = ''\r
657 for Item in List:\r
658 Str = Str + Item + Split\r
659 return Str.strip()\r
660\r
661## Get HelpTextList\r
662#\r
663# Get HelpTextList from HelpTextClassList\r
664#\r
665# @param HelpTextClassList: Help Text Class List\r
666#\r
667def GetHelpTextList(HelpTextClassList):\r
668 List = []\r
669 if HelpTextClassList:\r
670 for HelpText in HelpTextClassList:\r
671 if HelpText.String.endswith('\n'):\r
672 HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')]\r
673 List.extend(HelpText.String.split('\n'))\r
674 return List\r
675\r
676## Get String Array Length\r
677#\r
678# Get String Array Length\r
679#\r
680# @param String: the source string\r
681#\r
682def StringArrayLength(String):\r
683 if isinstance(String, unicode):\r
684 return (len(String) + 1) * 2 + 1\r
685 elif String.startswith('L"'):\r
686 return (len(String) - 3 + 1) * 2\r
687 elif String.startswith('"'):\r
688 return (len(String) - 2 + 1)\r
689 else:\r
690 return len(String.split()) + 1\r
691\r
692## RemoveDupOption\r
693#\r
694# Remove Dup Option\r
695#\r
696# @param OptionString: the option string\r
697# @param Which: Which flag\r
698# @param Against: Against flag\r
421ccda3 699#\r
4234283c
LG
700def RemoveDupOption(OptionString, Which="/I", Against=None):\r
701 OptionList = OptionString.split()\r
702 ValueList = []\r
703 if Against:\r
704 ValueList += Against\r
705 for Index in range(len(OptionList)):\r
706 Opt = OptionList[Index]\r
707 if not Opt.startswith(Which):\r
708 continue\r
709 if len(Opt) > len(Which):\r
710 Val = Opt[len(Which):]\r
711 else:\r
712 Val = ""\r
713 if Val in ValueList:\r
714 OptionList[Index] = ""\r
715 else:\r
716 ValueList.append(Val)\r
717 return " ".join(OptionList)\r
718\r
719## Check if the string is HexDgit\r
720#\r
421ccda3
HC
721# Return true if all characters in the string are digits and there is at\r
722# least one character\r
4234283c 723# or valid Hexs (started with 0x, following by hexdigit letters)\r
421ccda3 724# , false otherwise.\r
4234283c
LG
725# @param string: input string\r
726#\r
727def IsHexDigit(Str):\r
421ccda3 728 try:\r
4234283c
LG
729 int(Str, 10)\r
730 return True\r
731 except ValueError:\r
732 if len(Str) > 2 and Str.upper().startswith('0X'):\r
733 try:\r
734 int(Str, 16)\r
735 return True\r
736 except ValueError:\r
737 return False\r
738 return False\r
739\r
421ccda3 740## Check if the string is HexDgit and its interger value within limit of UINT32\r
4234283c 741#\r
421ccda3
HC
742# Return true if all characters in the string are digits and there is at\r
743# least one character\r
4234283c 744# or valid Hexs (started with 0x, following by hexdigit letters)\r
421ccda3 745# , false otherwise.\r
4234283c
LG
746# @param string: input string\r
747#\r
748def IsHexDigitUINT32(Str):\r
421ccda3 749 try:\r
4234283c
LG
750 Value = int(Str, 10)\r
751 if (Value <= 0xFFFFFFFF) and (Value >= 0):\r
752 return True\r
753 except ValueError:\r
754 if len(Str) > 2 and Str.upper().startswith('0X'):\r
755 try:\r
756 Value = int(Str, 16)\r
757 if (Value <= 0xFFFFFFFF) and (Value >= 0):\r
758 return True\r
759 except ValueError:\r
760 return False\r
761 return False\r
762\r
763## CleanSpecialChar\r
421ccda3
HC
764#\r
765# The ASCII text files of type INF, DEC, INI are edited by developers,\r
4234283c 766# and may contain characters that cannot be directly translated to strings that\r
421ccda3
HC
767# are conformant with the UDP XML Schema. Any characters in this category\r
768# (0x00-0x08, TAB [0x09], 0x0B, 0x0C, 0x0E-0x1F, 0x80-0xFF)\r
4234283c
LG
769# must be converted to a space character[0x20] as part of the parsing process.\r
770#\r
771def ConvertSpecialChar(Lines):\r
772 RetLines = []\r
773 for line in Lines:\r
774 ReMatchSpecialChar = re.compile(r"[\x00-\x08]|\x09|\x0b|\x0c|[\x0e-\x1f]|[\x7f-\xff]")\r
775 RetLines.append(ReMatchSpecialChar.sub(' ', line))\r
421ccda3 776\r
4234283c
LG
777 return RetLines\r
778\r
779## __GetTokenList\r
780#\r
781# Assume Str is a valid feature flag expression.\r
782# Return a list which contains tokens: alpha numeric token and other token\r
783# Whitespace are not stripped\r
784#\r
785def __GetTokenList(Str):\r
786 InQuote = False\r
787 Token = ''\r
788 TokenOP = ''\r
789 PreChar = ''\r
790 List = []\r
791 for Char in Str:\r
792 if InQuote:\r
793 Token += Char\r
794 if Char == '"' and PreChar != '\\':\r
795 InQuote = not InQuote\r
796 List.append(Token)\r
797 Token = ''\r
798 continue\r
799 if Char == '"':\r
800 if Token and Token != 'L':\r
801 List.append(Token)\r
802 Token = ''\r
803 if TokenOP:\r
804 List.append(TokenOP)\r
805 TokenOP = ''\r
806 InQuote = not InQuote\r
807 Token += Char\r
808 continue\r
809\r
810 if not (Char.isalnum() or Char in '_'):\r
811 TokenOP += Char\r
812 if Token:\r
813 List.append(Token)\r
814 Token = ''\r
815 else:\r
816 Token += Char\r
817 if TokenOP:\r
818 List.append(TokenOP)\r
819 TokenOP = ''\r
421ccda3 820\r
4234283c
LG
821 if PreChar == '\\' and Char == '\\':\r
822 PreChar = ''\r
823 else:\r
824 PreChar = Char\r
825 if Token:\r
826 List.append(Token)\r
827 if TokenOP:\r
828 List.append(TokenOP)\r
829 return List\r
830\r
831## ConvertNEToNOTEQ\r
832#\r
833# Convert NE operator to NOT EQ\r
834# For example: 1 NE 2 -> 1 NOT EQ 2\r
835#\r
836# @param Expr: Feature flag expression to be converted\r
837#\r
838def ConvertNEToNOTEQ(Expr):\r
839 List = __GetTokenList(Expr)\r
840 for Index in range(len(List)):\r
841 if List[Index] == 'NE':\r
842 List[Index] = 'NOT EQ'\r
843 return ''.join(List)\r
844\r
845## ConvertNOTEQToNE\r
846#\r
847# Convert NOT EQ operator to NE\r
848# For example: 1 NOT NE 2 -> 1 NE 2\r
849#\r
850# @param Expr: Feature flag expression to be converted\r
851#\r
852def ConvertNOTEQToNE(Expr):\r
853 List = __GetTokenList(Expr)\r
854 HasNOT = False\r
855 RetList = []\r
856 for Token in List:\r
857 if HasNOT and Token == 'EQ':\r
858 # At least, 'NOT' is in the list\r
859 while not RetList[-1].strip():\r
860 RetList.pop()\r
861 RetList[-1] = 'NE'\r
862 HasNOT = False\r
863 continue\r
864 if Token == 'NOT':\r
865 HasNOT = True\r
866 elif Token.strip():\r
867 HasNOT = False\r
868 RetList.append(Token)\r
869\r
870 return ''.join(RetList)\r
871\r
872## SplitPcdEntry\r
421ccda3 873#\r
4234283c
LG
874# Split an PCD entry string to Token.CName and PCD value and FFE.\r
875# NOTE: PCD Value and FFE can contain "|" in it's expression. And in INF specification, have below rule.\r
421ccda3 876# When using the characters "|" or "||" in an expression, the expression must be encapsulated in\r
4234283c 877# open "(" and close ")" parenthesis.\r
421ccda3 878#\r
4234283c 879# @param String An PCD entry string need to be split.\r
421ccda3
HC
880#\r
881# @return List [PcdTokenCName, Value, FFE]\r
4234283c
LG
882#\r
883def SplitPcdEntry(String):\r
884 if not String:\r
421ccda3
HC
885 return ['', '', ''], False\r
886\r
4234283c
LG
887 PcdTokenCName = ''\r
888 PcdValue = ''\r
889 PcdFeatureFlagExp = ''\r
421ccda3 890\r
4234283c 891 ValueList = GetSplitValueList(String, "|", 1)\r
421ccda3 892\r
4234283c
LG
893 #\r
894 # Only contain TokenCName\r
895 #\r
896 if len(ValueList) == 1:\r
897 return [ValueList[0]], True\r
421ccda3 898\r
4234283c 899 NewValueList = []\r
421ccda3 900\r
4234283c
LG
901 if len(ValueList) == 2:\r
902 PcdTokenCName = ValueList[0]\r
421ccda3
HC
903\r
904 InQuote = False\r
905 InParenthesis = False\r
906 StrItem = ''\r
907 for StrCh in ValueList[1]:\r
908 if StrCh == '"':\r
909 InQuote = not InQuote\r
910 elif StrCh == '(' or StrCh == ')':\r
911 InParenthesis = not InParenthesis\r
912\r
913 if StrCh == '|':\r
914 if not InQuote or not InParenthesis:\r
915 NewValueList.append(StrItem.strip())\r
916 StrItem = ' '\r
917 continue\r
918\r
919 StrItem += StrCh\r
920\r
921 NewValueList.append(StrItem.strip())\r
4234283c
LG
922\r
923 if len(NewValueList) == 1:\r
924 PcdValue = NewValueList[0]\r
925 return [PcdTokenCName, PcdValue], True\r
926 elif len(NewValueList) == 2:\r
927 PcdValue = NewValueList[0]\r
928 PcdFeatureFlagExp = NewValueList[1]\r
929 return [PcdTokenCName, PcdValue, PcdFeatureFlagExp], True\r
930 else:\r
931 return ['', '', ''], False\r
421ccda3 932\r
4234283c 933 return ['', '', ''], False\r
e4ac870f
LG
934\r
935## Check if two arches matched?\r
936#\r
937# @param Arch1\r
938# @param Arch2\r
939#\r
940def IsMatchArch(Arch1, Arch2):\r
941 if 'COMMON' in Arch1 or 'COMMON' in Arch2:\r
942 return True\r
943 if isinstance(Arch1, basestring) and isinstance(Arch2, basestring):\r
944 if Arch1 == Arch2:\r
945 return True\r
946\r
947 if isinstance(Arch1, basestring) and isinstance(Arch2, list):\r
948 return Arch1 in Arch2\r
949\r
950 if isinstance(Arch2, basestring) and isinstance(Arch1, list):\r
951 return Arch2 in Arch1\r
952\r
953 if isinstance(Arch1, list) and isinstance(Arch2, list):\r
954 for Item1 in Arch1:\r
955 for Item2 in Arch2:\r
956 if Item1 == Item2:\r
957 return True\r
958\r
959 return False\r
06eb3540
HC
960\r
961# Search all files in FilePath to find the FileName with the largest index\r
962# Return the FileName with index +1 under the FilePath\r
963#\r
964def GetUniFileName(FilePath, FileName):\r
9e730bd1
HC
965 Files = []\r
966 try:\r
967 Files = os.listdir(FilePath)\r
968 except:\r
969 pass\r
970\r
06eb3540 971 LargestIndex = -1\r
f71b1630 972 IndexNotFound = True\r
06eb3540
HC
973 for File in Files:\r
974 if File.upper().startswith(FileName.upper()) and File.upper().endswith('.UNI'):\r
975 Index = File.upper().replace(FileName.upper(), '').replace('.UNI', '')\r
976 if Index:\r
977 try:\r
978 Index = int(Index)\r
979 except Exception:\r
980 Index = -1\r
981 else:\r
f71b1630 982 IndexNotFound = False\r
06eb3540
HC
983 Index = 0\r
984 if Index > LargestIndex:\r
985 LargestIndex = Index + 1\r
986\r
f71b1630 987 if LargestIndex > -1 and not IndexNotFound:\r
06eb3540
HC
988 return os.path.normpath(os.path.join(FilePath, FileName + str(LargestIndex) + '.uni'))\r
989 else:\r
990 return os.path.normpath(os.path.join(FilePath, FileName + '.uni'))\r