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