]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Common/Misc.py
BaseTools: Remove the old python "not-equal"
[mirror_edk2.git] / BaseTools / Source / Python / Common / Misc.py
CommitLineData
f51461c8
LG
1## @file\r
2# Common routines used by all tools\r
3#\r
d5988a8a 4# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
f51461c8
LG
5# This program and the accompanying materials\r
6# are licensed and made available under the terms and conditions of the BSD License\r
7# which accompanies this distribution. The full text of the license may be found at\r
8# http://opensource.org/licenses/bsd-license.php\r
9#\r
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12#\r
13\r
14##\r
15# Import Modules\r
16#\r
1be2ed90 17import Common.LongFilePathOs as os\r
f51461c8
LG
18import sys\r
19import string\r
20import thread\r
21import threading\r
22import time\r
23import re\r
24import cPickle\r
25import array\r
97fa0ee9 26import shutil\r
a3251d84 27from struct import pack\r
f51461c8
LG
28from UserDict import IterableUserDict\r
29from UserList import UserList\r
30\r
31from Common import EdkLogger as EdkLogger\r
32from Common import GlobalData as GlobalData\r
33from DataType import *\r
34from BuildToolError import *\r
35from CommonDataClass.DataClass import *\r
36from Parsing import GetSplitValueList\r
1be2ed90 37from Common.LongFilePathSupport import OpenLongFilePath as open\r
05cc51ad 38from Common.MultipleWorkspace import MultipleWorkspace as mws\r
ae7b6df8 39import uuid\r
726c501c 40from CommonDataClass.Exceptions import BadExpression\r
7dbc50bd 41import subprocess\r
f51461c8 42## Regular expression used to find out place holders in string template\r
47fea6af 43gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE | re.UNICODE)\r
f51461c8 44\r
1eb72acd
CJ
45## regular expressions for map file processing\r
46startPatternGeneral = re.compile("^Start[' ']+Length[' ']+Name[' ']+Class")\r
47addressPatternGeneral = re.compile("^Address[' ']+Publics by Value[' ']+Rva\+Base")\r
48valuePatternGcc = re.compile('^([\w_\.]+) +([\da-fA-Fx]+) +([\da-fA-Fx]+)$')\r
49pcdPatternGcc = re.compile('^([\da-fA-Fx]+) +([\da-fA-Fx]+)')\r
50secReGeneral = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\da-fA-F]+)[Hh]? +([.\w\$]+) +(\w+)', re.UNICODE)\r
51\r
f51461c8
LG
52## Dictionary used to store file time stamp for quick re-access\r
53gFileTimeStampCache = {} # {file path : file time stamp}\r
54\r
55## Dictionary used to store dependencies of files\r
56gDependencyDatabase = {} # arch : {file path : [dependent files list]}\r
57\r
22a99b87
YL
58def GetVariableOffset(mapfilepath, efifilepath, varnames):\r
59 """ Parse map file to get variable offset in current EFI file \r
60 @param mapfilepath Map file absolution path\r
61 @param efifilepath: EFI binary file full path\r
62 @param varnames iteratable container whose elements are variable names to be searched\r
63 \r
64 @return List whos elements are tuple with variable name and raw offset\r
65 """\r
66 lines = []\r
67 try:\r
68 f = open(mapfilepath, 'r')\r
69 lines = f.readlines()\r
70 f.close()\r
71 except:\r
72 return None\r
73 \r
74 if len(lines) == 0: return None\r
75 firstline = lines[0].strip()\r
76 if (firstline.startswith("Archive member included ") and\r
77 firstline.endswith(" file (symbol)")):\r
78 return _parseForGCC(lines, efifilepath, varnames)\r
14239ee0
YZ
79 if firstline.startswith("# Path:"):\r
80 return _parseForXcode(lines, efifilepath, varnames)\r
22a99b87
YL
81 return _parseGeneral(lines, efifilepath, varnames)\r
82\r
14239ee0
YZ
83def _parseForXcode(lines, efifilepath, varnames):\r
84 status = 0\r
85 ret = []\r
e52aed0d 86 for line in lines:\r
14239ee0
YZ
87 line = line.strip()\r
88 if status == 0 and line == "# Symbols:":\r
89 status = 1\r
90 continue\r
91 if status == 1 and len(line) != 0:\r
92 for varname in varnames:\r
93 if varname in line:\r
6686d9a1 94 # cannot pregenerate this RegEx since it uses varname from varnames.\r
14239ee0 95 m = re.match('^([\da-fA-FxX]+)([\s\S]*)([_]*%s)$' % varname, line)\r
4231a819 96 if m is not None:\r
14239ee0
YZ
97 ret.append((varname, m.group(1)))\r
98 return ret\r
99\r
22a99b87
YL
100def _parseForGCC(lines, efifilepath, varnames):\r
101 """ Parse map file generated by GCC linker """\r
102 status = 0\r
103 sections = []\r
104 varoffset = []\r
3e7e8571 105 for index, line in enumerate(lines):\r
22a99b87
YL
106 line = line.strip()\r
107 # status machine transection\r
108 if status == 0 and line == "Memory Configuration":\r
109 status = 1\r
110 continue\r
111 elif status == 1 and line == 'Linker script and memory map':\r
112 status = 2\r
113 continue\r
114 elif status ==2 and line == 'START GROUP':\r
115 status = 3\r
116 continue\r
117\r
118 # status handler\r
3e7e8571 119 if status == 3:\r
1eb72acd 120 m = valuePatternGcc.match(line)\r
4231a819 121 if m is not None:\r
22a99b87
YL
122 sections.append(m.groups(0))\r
123 for varname in varnames:\r
d03c056b
YZ
124 Str = ''\r
125 m = re.match("^.data.(%s)" % varname, line)\r
4231a819 126 if m is not None:\r
d03c056b 127 m = re.match(".data.(%s)$" % varname, line)\r
4231a819 128 if m is not None:\r
d03c056b
YZ
129 Str = lines[index + 1]\r
130 else:\r
131 Str = line[len(".data.%s" % varname):]\r
132 if Str:\r
1eb72acd 133 m = pcdPatternGcc.match(Str.strip())\r
4231a819 134 if m is not None:\r
3e7e8571 135 varoffset.append((varname, int(m.groups(0)[0], 16) , int(sections[-1][1], 16), sections[-1][0]))\r
22a99b87
YL
136\r
137 if not varoffset:\r
138 return []\r
139 # get section information from efi file\r
140 efisecs = PeImageClass(efifilepath).SectionHeaderList\r
4231a819 141 if efisecs is None or len(efisecs) == 0:\r
22a99b87
YL
142 return []\r
143 #redirection\r
144 redirection = 0\r
145 for efisec in efisecs:\r
146 for section in sections:\r
147 if section[0].strip() == efisec[0].strip() and section[0].strip() == '.text':\r
148 redirection = int(section[1], 16) - efisec[1]\r
149\r
150 ret = []\r
151 for var in varoffset:\r
152 for efisec in efisecs:\r
153 if var[1] >= efisec[1] and var[1] < efisec[1]+efisec[3]:\r
154 ret.append((var[0], hex(efisec[2] + var[1] - efisec[1] - redirection)))\r
155 return ret\r
156\r
157def _parseGeneral(lines, efifilepath, varnames):\r
158 status = 0 #0 - beginning of file; 1 - PE section definition; 2 - symbol table\r
159 secs = [] # key = section name\r
160 varoffset = []\r
22a99b87
YL
161 symRe = re.compile('^([\da-fA-F]+):([\da-fA-F]+) +([\.:\\\\\w\?@\$]+) +([\da-fA-F]+)', re.UNICODE)\r
162\r
163 for line in lines:\r
164 line = line.strip()\r
1eb72acd 165 if startPatternGeneral.match(line):\r
22a99b87
YL
166 status = 1\r
167 continue\r
1eb72acd 168 if addressPatternGeneral.match(line):\r
22a99b87
YL
169 status = 2\r
170 continue\r
6686d9a1 171 if line.startswith("entry point at"):\r
22a99b87
YL
172 status = 3\r
173 continue \r
174 if status == 1 and len(line) != 0:\r
1eb72acd 175 m = secReGeneral.match(line)\r
4231a819 176 assert m is not None, "Fail to parse the section in map file , line is %s" % line\r
22a99b87
YL
177 sec_no, sec_start, sec_length, sec_name, sec_class = m.groups(0)\r
178 secs.append([int(sec_no, 16), int(sec_start, 16), int(sec_length, 16), sec_name, sec_class])\r
179 if status == 2 and len(line) != 0:\r
180 for varname in varnames:\r
181 m = symRe.match(line)\r
4231a819 182 assert m is not None, "Fail to parse the symbol in map file, line is %s" % line\r
22a99b87
YL
183 sec_no, sym_offset, sym_name, vir_addr = m.groups(0)\r
184 sec_no = int(sec_no, 16)\r
185 sym_offset = int(sym_offset, 16)\r
186 vir_addr = int(vir_addr, 16)\r
6686d9a1 187 # cannot pregenerate this RegEx since it uses varname from varnames.\r
22a99b87 188 m2 = re.match('^[_]*(%s)' % varname, sym_name)\r
4231a819 189 if m2 is not None:\r
22a99b87
YL
190 # fond a binary pcd entry in map file\r
191 for sec in secs:\r
192 if sec[0] == sec_no and (sym_offset >= sec[1] and sym_offset < sec[1] + sec[2]):\r
193 varoffset.append([varname, sec[3], sym_offset, vir_addr, sec_no])\r
194\r
195 if not varoffset: return []\r
196\r
197 # get section information from efi file\r
198 efisecs = PeImageClass(efifilepath).SectionHeaderList\r
4231a819 199 if efisecs is None or len(efisecs) == 0:\r
22a99b87
YL
200 return []\r
201\r
202 ret = []\r
203 for var in varoffset:\r
204 index = 0\r
205 for efisec in efisecs:\r
206 index = index + 1\r
207 if var[1].strip() == efisec[0].strip():\r
208 ret.append((var[0], hex(efisec[2] + var[2])))\r
209 elif var[4] == index:\r
210 ret.append((var[0], hex(efisec[2] + var[2])))\r
211\r
212 return ret\r
213\r
97fa0ee9
YL
214## Routine to process duplicated INF\r
215#\r
216# This function is called by following two cases:\r
217# Case 1 in DSC:\r
218# [components.arch]\r
219# Pkg/module/module.inf\r
220# Pkg/module/module.inf {\r
221# <Defines>\r
222# FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836\r
223# }\r
224# Case 2 in FDF:\r
225# INF Pkg/module/module.inf\r
226# INF FILE_GUID = 0D1B936F-68F3-4589-AFCC-FB8B7AEBC836 Pkg/module/module.inf\r
227#\r
228# This function copies Pkg/module/module.inf to\r
229# Conf/.cache/0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf\r
230#\r
231# @param Path Original PathClass object\r
232# @param BaseName New file base name\r
233#\r
234# @retval return the new PathClass object\r
235#\r
236def ProcessDuplicatedInf(Path, BaseName, Workspace):\r
237 Filename = os.path.split(Path.File)[1]\r
238 if '.' in Filename:\r
239 Filename = BaseName + Path.BaseName + Filename[Filename.rfind('.'):]\r
240 else:\r
241 Filename = BaseName + Path.BaseName\r
242\r
243 #\r
244 # If -N is specified on command line, cache is disabled\r
245 # The directory has to be created\r
246 #\r
247 DbDir = os.path.split(GlobalData.gDatabasePath)[0]\r
248 if not os.path.exists(DbDir):\r
249 os.makedirs(DbDir)\r
250 #\r
251 # A temporary INF is copied to database path which must have write permission\r
252 # The temporary will be removed at the end of build\r
253 # In case of name conflict, the file name is \r
254 # FILE_GUIDBaseName (0D1B936F-68F3-4589-AFCC-FB8B7AEBC836module.inf)\r
255 #\r
256 TempFullPath = os.path.join(DbDir,\r
257 Filename)\r
258 RtPath = PathClass(Path.File, Workspace)\r
259 #\r
260 # Modify the full path to temporary path, keep other unchanged\r
261 #\r
262 # To build same module more than once, the module path with FILE_GUID overridden has\r
263 # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path\r
264 # in DSC which is used as relative path by C files and other files in INF. \r
265 # A trick was used: all module paths are PathClass instances, after the initialization\r
266 # of PathClass, the PathClass.Path is overridden by the temporary INF path.\r
267 #\r
268 # The reason for creating a temporary INF is:\r
269 # Platform.Modules which is the base to create ModuleAutoGen objects is a dictionary,\r
270 # the key is the full path of INF, the value is an object to save overridden library instances, PCDs.\r
271 # A different key for the same module is needed to create different output directory,\r
272 # retrieve overridden PCDs, library instances.\r
273 #\r
274 # The BaseName is the FILE_GUID which is also the output directory name.\r
275 #\r
276 #\r
277 RtPath.Path = TempFullPath\r
278 RtPath.BaseName = BaseName\r
279 #\r
280 # If file exists, compare contents\r
281 #\r
282 if os.path.exists(TempFullPath):\r
283 with open(str(Path), 'rb') as f1: Src = f1.read()\r
284 with open(TempFullPath, 'rb') as f2: Dst = f2.read()\r
285 if Src == Dst:\r
286 return RtPath\r
287 GlobalData.gTempInfs.append(TempFullPath)\r
288 shutil.copy2(str(Path), TempFullPath)\r
289 return RtPath\r
290\r
291## Remove temporary created INFs whose paths were saved in gTempInfs\r
292#\r
293def ClearDuplicatedInf():\r
294 for File in GlobalData.gTempInfs:\r
295 if os.path.exists(File):\r
296 os.remove(File)\r
297\r
f51461c8
LG
298## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style\r
299#\r
300# @param Guid The GUID string\r
301#\r
302# @retval string The GUID string in C structure style\r
303#\r
304def GuidStringToGuidStructureString(Guid):\r
305 GuidList = Guid.split('-')\r
306 Result = '{'\r
47fea6af 307 for Index in range(0, 3, 1):\r
f51461c8
LG
308 Result = Result + '0x' + GuidList[Index] + ', '\r
309 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
47fea6af
YZ
310 for Index in range(0, 12, 2):\r
311 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]\r
f51461c8
LG
312 Result += '}}'\r
313 return Result\r
314\r
315## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
316#\r
317# @param GuidValue The GUID value in byte array\r
318#\r
319# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
320#\r
321def GuidStructureByteArrayToGuidString(GuidValue):\r
322 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
323 guidValueList = guidValueString.split(",")\r
324 if len(guidValueList) != 16:\r
325 return ''\r
326 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
327 try:\r
328 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
329 int(guidValueList[3], 16),\r
330 int(guidValueList[2], 16),\r
331 int(guidValueList[1], 16),\r
332 int(guidValueList[0], 16),\r
333 int(guidValueList[5], 16),\r
334 int(guidValueList[4], 16),\r
335 int(guidValueList[7], 16),\r
336 int(guidValueList[6], 16),\r
337 int(guidValueList[8], 16),\r
338 int(guidValueList[9], 16),\r
339 int(guidValueList[10], 16),\r
340 int(guidValueList[11], 16),\r
341 int(guidValueList[12], 16),\r
342 int(guidValueList[13], 16),\r
343 int(guidValueList[14], 16),\r
344 int(guidValueList[15], 16)\r
345 )\r
346 except:\r
347 return ''\r
348\r
349## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
350#\r
351# @param GuidValue The GUID value in C structure format\r
352#\r
353# @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
354#\r
355def GuidStructureStringToGuidString(GuidValue):\r
356 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")\r
357 guidValueList = guidValueString.split(",")\r
358 if len(guidValueList) != 11:\r
359 return ''\r
360 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
361 try:\r
362 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
363 int(guidValueList[0], 16),\r
364 int(guidValueList[1], 16),\r
365 int(guidValueList[2], 16),\r
366 int(guidValueList[3], 16),\r
367 int(guidValueList[4], 16),\r
368 int(guidValueList[5], 16),\r
369 int(guidValueList[6], 16),\r
370 int(guidValueList[7], 16),\r
371 int(guidValueList[8], 16),\r
372 int(guidValueList[9], 16),\r
373 int(guidValueList[10], 16)\r
374 )\r
375 except:\r
376 return ''\r
377\r
378## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx\r
379#\r
380# @param GuidValue The GUID value in C structure format\r
381#\r
382# @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format\r
383#\r
384def GuidStructureStringToGuidValueName(GuidValue):\r
385 guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")\r
386 guidValueList = guidValueString.split(",")\r
387 if len(guidValueList) != 11:\r
388 EdkLogger.error(None, FORMAT_INVALID, "Invalid GUID value string [%s]" % GuidValue)\r
389 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (\r
390 int(guidValueList[0], 16),\r
391 int(guidValueList[1], 16),\r
392 int(guidValueList[2], 16),\r
393 int(guidValueList[3], 16),\r
394 int(guidValueList[4], 16),\r
395 int(guidValueList[5], 16),\r
396 int(guidValueList[6], 16),\r
397 int(guidValueList[7], 16),\r
398 int(guidValueList[8], 16),\r
399 int(guidValueList[9], 16),\r
400 int(guidValueList[10], 16)\r
401 )\r
402\r
403## Create directories\r
404#\r
405# @param Directory The directory name\r
406#\r
407def CreateDirectory(Directory):\r
4231a819 408 if Directory is None or Directory.strip() == "":\r
f51461c8
LG
409 return True\r
410 try:\r
411 if not os.access(Directory, os.F_OK):\r
412 os.makedirs(Directory)\r
413 except:\r
414 return False\r
415 return True\r
416\r
417## Remove directories, including files and sub-directories in it\r
418#\r
419# @param Directory The directory name\r
420#\r
421def RemoveDirectory(Directory, Recursively=False):\r
4231a819 422 if Directory is None or Directory.strip() == "" or not os.path.exists(Directory):\r
f51461c8
LG
423 return\r
424 if Recursively:\r
425 CurrentDirectory = os.getcwd()\r
426 os.chdir(Directory)\r
427 for File in os.listdir("."):\r
428 if os.path.isdir(File):\r
429 RemoveDirectory(File, Recursively)\r
430 else:\r
431 os.remove(File)\r
432 os.chdir(CurrentDirectory)\r
433 os.rmdir(Directory)\r
434\r
f51461c8
LG
435## Store content in file\r
436#\r
437# This method is used to save file only when its content is changed. This is\r
438# quite useful for "make" system to decide what will be re-built and what won't.\r
439#\r
440# @param File The path of file\r
441# @param Content The new content of the file\r
442# @param IsBinaryFile The flag indicating if the file is binary file or not\r
443#\r
444# @retval True If the file content is changed and the file is renewed\r
445# @retval False If the file content is the same\r
446#\r
447def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
448 if not IsBinaryFile:\r
449 Content = Content.replace("\n", os.linesep)\r
450\r
451 if os.path.exists(File):\r
452 try:\r
453 if Content == open(File, "rb").read():\r
454 return False\r
455 except:\r
456 EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)\r
457\r
458 DirName = os.path.dirname(File)\r
459 if not CreateDirectory(DirName):\r
460 EdkLogger.error(None, FILE_CREATE_FAILURE, "Could not create directory %s" % DirName)\r
461 else:\r
462 if DirName == '':\r
463 DirName = os.getcwd()\r
464 if not os.access(DirName, os.W_OK):\r
465 EdkLogger.error(None, PERMISSION_FAILURE, "Do not have write permission on directory %s" % DirName)\r
466\r
467 try:\r
468 if GlobalData.gIsWindows:\r
469 try:\r
470 from PyUtility import SaveFileToDisk\r
471 if not SaveFileToDisk(File, Content):\r
472 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)\r
473 except:\r
474 Fd = open(File, "wb")\r
475 Fd.write(Content)\r
476 Fd.close()\r
477 else:\r
478 Fd = open(File, "wb")\r
479 Fd.write(Content)\r
480 Fd.close()\r
5b0671c1 481 except IOError as X:\r
47fea6af 482 EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData='IOError %s' % X)\r
f51461c8
LG
483\r
484 return True\r
485\r
486## Make a Python object persistent on file system\r
487#\r
488# @param Data The object to be stored in file\r
489# @param File The path of file to store the object\r
490#\r
491def DataDump(Data, File):\r
492 Fd = None\r
493 try:\r
494 Fd = open(File, 'wb')\r
495 cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)\r
496 except:\r
497 EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)\r
498 finally:\r
4231a819 499 if Fd is not None:\r
f51461c8
LG
500 Fd.close()\r
501\r
502## Restore a Python object from a file\r
503#\r
504# @param File The path of file stored the object\r
505#\r
506# @retval object A python object\r
507# @retval None If failure in file operation\r
508#\r
509def DataRestore(File):\r
510 Data = None\r
511 Fd = None\r
512 try:\r
513 Fd = open(File, 'rb')\r
514 Data = cPickle.load(Fd)\r
5b0671c1 515 except Exception as e:\r
f51461c8
LG
516 EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))\r
517 Data = None\r
518 finally:\r
4231a819 519 if Fd is not None:\r
f51461c8
LG
520 Fd.close()\r
521 return Data\r
522\r
523## Retrieve and cache the real path name in file system\r
524#\r
525# @param Root The root directory of path relative to\r
526#\r
527# @retval str The path string if the path exists\r
528# @retval None If path doesn't exist\r
529#\r
530class DirCache:\r
531 _CACHE_ = set()\r
532 _UPPER_CACHE_ = {}\r
533\r
534 def __init__(self, Root):\r
535 self._Root = Root\r
536 for F in os.listdir(Root):\r
537 self._CACHE_.add(F)\r
538 self._UPPER_CACHE_[F.upper()] = F\r
539\r
540 # =[] operator\r
541 def __getitem__(self, Path):\r
542 Path = Path[len(os.path.commonprefix([Path, self._Root])):]\r
543 if not Path:\r
544 return self._Root\r
545 if Path and Path[0] == os.path.sep:\r
546 Path = Path[1:]\r
547 if Path in self._CACHE_:\r
548 return os.path.join(self._Root, Path)\r
549 UpperPath = Path.upper()\r
550 if UpperPath in self._UPPER_CACHE_:\r
551 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
552\r
553 IndexList = []\r
554 LastSepIndex = -1\r
555 SepIndex = Path.find(os.path.sep)\r
556 while SepIndex > -1:\r
557 Parent = UpperPath[:SepIndex]\r
558 if Parent not in self._UPPER_CACHE_:\r
559 break\r
560 LastSepIndex = SepIndex\r
561 SepIndex = Path.find(os.path.sep, LastSepIndex + 1)\r
562\r
563 if LastSepIndex == -1:\r
564 return None\r
565\r
566 Cwd = os.getcwd()\r
567 os.chdir(self._Root)\r
568 SepIndex = LastSepIndex\r
569 while SepIndex > -1:\r
570 Parent = Path[:SepIndex]\r
571 ParentKey = UpperPath[:SepIndex]\r
572 if ParentKey not in self._UPPER_CACHE_:\r
573 os.chdir(Cwd)\r
574 return None\r
575\r
576 if Parent in self._CACHE_:\r
577 ParentDir = Parent\r
578 else:\r
579 ParentDir = self._UPPER_CACHE_[ParentKey]\r
580 for F in os.listdir(ParentDir):\r
581 Dir = os.path.join(ParentDir, F)\r
582 self._CACHE_.add(Dir)\r
583 self._UPPER_CACHE_[Dir.upper()] = Dir\r
584\r
585 SepIndex = Path.find(os.path.sep, SepIndex + 1)\r
586\r
587 os.chdir(Cwd)\r
588 if Path in self._CACHE_:\r
589 return os.path.join(self._Root, Path)\r
590 elif UpperPath in self._UPPER_CACHE_:\r
591 return os.path.join(self._Root, self._UPPER_CACHE_[UpperPath])\r
592 return None\r
593\r
f51461c8
LG
594def RealPath(File, Dir='', OverrideDir=''):\r
595 NewFile = os.path.normpath(os.path.join(Dir, File))\r
596 NewFile = GlobalData.gAllFiles[NewFile]\r
597 if not NewFile and OverrideDir:\r
598 NewFile = os.path.normpath(os.path.join(OverrideDir, File))\r
599 NewFile = GlobalData.gAllFiles[NewFile]\r
600 return NewFile\r
601\r
602def RealPath2(File, Dir='', OverrideDir=''):\r
9b9500a1 603 NewFile = None\r
f51461c8
LG
604 if OverrideDir:\r
605 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(OverrideDir, File))]\r
606 if NewFile:\r
607 if OverrideDir[-1] == os.path.sep:\r
608 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]\r
609 else:\r
47fea6af 610 return NewFile[len(OverrideDir) + 1:], NewFile[0:len(OverrideDir)]\r
f51461c8
LG
611 if GlobalData.gAllFiles:\r
612 NewFile = GlobalData.gAllFiles[os.path.normpath(os.path.join(Dir, File))]\r
9b9500a1 613 if not NewFile:\r
f51461c8 614 NewFile = os.path.normpath(os.path.join(Dir, File))\r
9b9500a1
YL
615 if not os.path.exists(NewFile):\r
616 return None, None\r
f51461c8
LG
617 if NewFile:\r
618 if Dir:\r
619 if Dir[-1] == os.path.sep:\r
620 return NewFile[len(Dir):], NewFile[0:len(Dir)]\r
621 else:\r
47fea6af 622 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]\r
f51461c8
LG
623 else:\r
624 return NewFile, ''\r
625\r
626 return None, None\r
627\r
f51461c8
LG
628## Get GUID value from given packages\r
629#\r
630# @param CName The CName of the GUID\r
631# @param PackageList List of packages looking-up in\r
c28d2e10 632# @param Inffile The driver file\r
f51461c8
LG
633#\r
634# @retval GuidValue if the CName is found in any given package\r
635# @retval None if the CName is not found in all given packages\r
636#\r
c28d2e10 637def GuidValue(CName, PackageList, Inffile = None):\r
f51461c8 638 for P in PackageList:\r
c28d2e10
YZ
639 GuidKeys = P.Guids.keys()\r
640 if Inffile and P._PrivateGuids:\r
641 if not Inffile.startswith(P.MetaFile.Dir):\r
175a4b5d 642 GuidKeys = [x for x in P.Guids if x not in P._PrivateGuids]\r
c28d2e10 643 if CName in GuidKeys:\r
f51461c8
LG
644 return P.Guids[CName]\r
645 return None\r
646\r
647## Get Protocol value from given packages\r
648#\r
649# @param CName The CName of the GUID\r
650# @param PackageList List of packages looking-up in\r
c28d2e10 651# @param Inffile The driver file\r
f51461c8
LG
652#\r
653# @retval GuidValue if the CName is found in any given package\r
654# @retval None if the CName is not found in all given packages\r
655#\r
c28d2e10 656def ProtocolValue(CName, PackageList, Inffile = None):\r
f51461c8 657 for P in PackageList:\r
c28d2e10
YZ
658 ProtocolKeys = P.Protocols.keys()\r
659 if Inffile and P._PrivateProtocols:\r
660 if not Inffile.startswith(P.MetaFile.Dir):\r
175a4b5d 661 ProtocolKeys = [x for x in P.Protocols if x not in P._PrivateProtocols]\r
c28d2e10 662 if CName in ProtocolKeys:\r
f51461c8
LG
663 return P.Protocols[CName]\r
664 return None\r
665\r
666## Get PPI value from given packages\r
667#\r
668# @param CName The CName of the GUID\r
669# @param PackageList List of packages looking-up in\r
c28d2e10 670# @param Inffile The driver file\r
f51461c8
LG
671#\r
672# @retval GuidValue if the CName is found in any given package\r
673# @retval None if the CName is not found in all given packages\r
674#\r
c28d2e10 675def PpiValue(CName, PackageList, Inffile = None):\r
f51461c8 676 for P in PackageList:\r
c28d2e10
YZ
677 PpiKeys = P.Ppis.keys()\r
678 if Inffile and P._PrivatePpis:\r
679 if not Inffile.startswith(P.MetaFile.Dir):\r
175a4b5d 680 PpiKeys = [x for x in P.Ppis if x not in P._PrivatePpis]\r
c28d2e10 681 if CName in PpiKeys:\r
f51461c8
LG
682 return P.Ppis[CName]\r
683 return None\r
684\r
685## A string template class\r
686#\r
687# This class implements a template for string replacement. A string template\r
688# looks like following\r
689#\r
690# ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
691#\r
692# The string between ${BEGIN} and ${END} will be repeated as many times as the\r
693# length of "placeholder_name", which is a list passed through a dict. The\r
694# "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
695# be not used and, in this case, the "placeholder_name" must not a list and it\r
696# will just be replaced once.\r
697#\r
698class TemplateString(object):\r
699 _REPEAT_START_FLAG = "BEGIN"\r
700 _REPEAT_END_FLAG = "END"\r
701\r
702 class Section(object):\r
703 _LIST_TYPES = [type([]), type(set()), type((0,))]\r
704\r
705 def __init__(self, TemplateSection, PlaceHolderList):\r
706 self._Template = TemplateSection\r
707 self._PlaceHolderList = []\r
708\r
709 # Split the section into sub-sections according to the position of placeholders\r
710 if PlaceHolderList:\r
711 self._SubSectionList = []\r
712 SubSectionStart = 0\r
713 #\r
714 # The placeholders passed in must be in the format of\r
715 #\r
716 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint\r
717 #\r
47fea6af 718 for PlaceHolder, Start, End in PlaceHolderList:\r
f51461c8
LG
719 self._SubSectionList.append(TemplateSection[SubSectionStart:Start])\r
720 self._SubSectionList.append(TemplateSection[Start:End])\r
721 self._PlaceHolderList.append(PlaceHolder)\r
722 SubSectionStart = End\r
723 if SubSectionStart < len(TemplateSection):\r
724 self._SubSectionList.append(TemplateSection[SubSectionStart:])\r
725 else:\r
726 self._SubSectionList = [TemplateSection]\r
727\r
728 def __str__(self):\r
729 return self._Template + " : " + str(self._PlaceHolderList)\r
730\r
731 def Instantiate(self, PlaceHolderValues):\r
732 RepeatTime = -1\r
733 RepeatPlaceHolders = {}\r
734 NonRepeatPlaceHolders = {}\r
735\r
736 for PlaceHolder in self._PlaceHolderList:\r
737 if PlaceHolder not in PlaceHolderValues:\r
738 continue\r
739 Value = PlaceHolderValues[PlaceHolder]\r
740 if type(Value) in self._LIST_TYPES:\r
741 if RepeatTime < 0:\r
742 RepeatTime = len(Value)\r
743 elif RepeatTime != len(Value):\r
744 EdkLogger.error(\r
745 "TemplateString",\r
746 PARAMETER_INVALID,\r
747 "${%s} has different repeat time from others!" % PlaceHolder,\r
748 ExtraData=str(self._Template)\r
749 )\r
750 RepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
751 else:\r
752 NonRepeatPlaceHolders["${%s}" % PlaceHolder] = Value\r
753\r
754 if NonRepeatPlaceHolders:\r
755 StringList = []\r
756 for S in self._SubSectionList:\r
757 if S not in NonRepeatPlaceHolders:\r
758 StringList.append(S)\r
759 else:\r
760 StringList.append(str(NonRepeatPlaceHolders[S]))\r
761 else:\r
762 StringList = self._SubSectionList\r
763\r
764 if RepeatPlaceHolders:\r
765 TempStringList = []\r
766 for Index in range(RepeatTime):\r
767 for S in StringList:\r
768 if S not in RepeatPlaceHolders:\r
769 TempStringList.append(S)\r
770 else:\r
771 TempStringList.append(str(RepeatPlaceHolders[S][Index]))\r
772 StringList = TempStringList\r
773\r
774 return "".join(StringList)\r
775\r
776 ## Constructor\r
777 def __init__(self, Template=None):\r
778 self.String = ''\r
779 self.IsBinary = False\r
780 self._Template = Template\r
781 self._TemplateSectionList = self._Parse(Template)\r
782\r
783 ## str() operator\r
784 #\r
785 # @retval string The string replaced\r
786 #\r
787 def __str__(self):\r
788 return self.String\r
789\r
790 ## Split the template string into fragments per the ${BEGIN} and ${END} flags\r
791 #\r
792 # @retval list A list of TemplateString.Section objects\r
793 #\r
794 def _Parse(self, Template):\r
795 SectionStart = 0\r
796 SearchFrom = 0\r
797 MatchEnd = 0\r
798 PlaceHolderList = []\r
799 TemplateSectionList = []\r
800 while Template:\r
801 MatchObj = gPlaceholderPattern.search(Template, SearchFrom)\r
802 if not MatchObj:\r
803 if MatchEnd <= len(Template):\r
804 TemplateSection = TemplateString.Section(Template[SectionStart:], PlaceHolderList)\r
805 TemplateSectionList.append(TemplateSection)\r
806 break\r
807\r
808 MatchString = MatchObj.group(1)\r
809 MatchStart = MatchObj.start()\r
810 MatchEnd = MatchObj.end()\r
811\r
812 if MatchString == self._REPEAT_START_FLAG:\r
813 if MatchStart > SectionStart:\r
814 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
815 TemplateSectionList.append(TemplateSection)\r
816 SectionStart = MatchEnd\r
817 PlaceHolderList = []\r
818 elif MatchString == self._REPEAT_END_FLAG:\r
819 TemplateSection = TemplateString.Section(Template[SectionStart:MatchStart], PlaceHolderList)\r
820 TemplateSectionList.append(TemplateSection)\r
821 SectionStart = MatchEnd\r
822 PlaceHolderList = []\r
823 else:\r
824 PlaceHolderList.append((MatchString, MatchStart - SectionStart, MatchEnd - SectionStart))\r
825 SearchFrom = MatchEnd\r
826 return TemplateSectionList\r
827\r
828 ## Replace the string template with dictionary of placeholders and append it to previous one\r
829 #\r
830 # @param AppendString The string template to append\r
831 # @param Dictionary The placeholder dictionaries\r
832 #\r
833 def Append(self, AppendString, Dictionary=None):\r
834 if Dictionary:\r
835 SectionList = self._Parse(AppendString)\r
8252e6bf 836 self.String += "".join(S.Instantiate(Dictionary) for S in SectionList)\r
f51461c8
LG
837 else:\r
838 self.String += AppendString\r
839\r
840 ## Replace the string template with dictionary of placeholders\r
841 #\r
842 # @param Dictionary The placeholder dictionaries\r
843 #\r
844 # @retval str The string replaced with placeholder values\r
845 #\r
846 def Replace(self, Dictionary=None):\r
8252e6bf 847 return "".join(S.Instantiate(Dictionary) for S in self._TemplateSectionList)\r
f51461c8
LG
848\r
849## Progress indicator class\r
850#\r
851# This class makes use of thread to print progress on console.\r
852#\r
853class Progressor:\r
854 # for avoiding deadloop\r
855 _StopFlag = None\r
856 _ProgressThread = None\r
857 _CheckInterval = 0.25\r
858\r
859 ## Constructor\r
860 #\r
861 # @param OpenMessage The string printed before progress charaters\r
862 # @param CloseMessage The string printed after progress charaters\r
863 # @param ProgressChar The charater used to indicate the progress\r
864 # @param Interval The interval in seconds between two progress charaters\r
865 #\r
866 def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1.0):\r
867 self.PromptMessage = OpenMessage\r
868 self.CodaMessage = CloseMessage\r
869 self.ProgressChar = ProgressChar\r
870 self.Interval = Interval\r
4231a819 871 if Progressor._StopFlag is None:\r
f51461c8
LG
872 Progressor._StopFlag = threading.Event()\r
873\r
874 ## Start to print progress charater\r
875 #\r
876 # @param OpenMessage The string printed before progress charaters\r
877 #\r
878 def Start(self, OpenMessage=None):\r
4231a819 879 if OpenMessage is not None:\r
f51461c8
LG
880 self.PromptMessage = OpenMessage\r
881 Progressor._StopFlag.clear()\r
4231a819 882 if Progressor._ProgressThread is None:\r
f51461c8
LG
883 Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
884 Progressor._ProgressThread.setDaemon(False)\r
885 Progressor._ProgressThread.start()\r
886\r
887 ## Stop printing progress charater\r
888 #\r
889 # @param CloseMessage The string printed after progress charaters\r
890 #\r
891 def Stop(self, CloseMessage=None):\r
892 OriginalCodaMessage = self.CodaMessage\r
4231a819 893 if CloseMessage is not None:\r
f51461c8
LG
894 self.CodaMessage = CloseMessage\r
895 self.Abort()\r
896 self.CodaMessage = OriginalCodaMessage\r
897\r
898 ## Thread entry method\r
899 def _ProgressThreadEntry(self):\r
900 sys.stdout.write(self.PromptMessage + " ")\r
901 sys.stdout.flush()\r
902 TimeUp = 0.0\r
903 while not Progressor._StopFlag.isSet():\r
904 if TimeUp <= 0.0:\r
905 sys.stdout.write(self.ProgressChar)\r
906 sys.stdout.flush()\r
907 TimeUp = self.Interval\r
908 time.sleep(self._CheckInterval)\r
909 TimeUp -= self._CheckInterval\r
910 sys.stdout.write(" " + self.CodaMessage + "\n")\r
911 sys.stdout.flush()\r
912\r
913 ## Abort the progress display\r
914 @staticmethod\r
915 def Abort():\r
4231a819 916 if Progressor._StopFlag is not None:\r
f51461c8 917 Progressor._StopFlag.set()\r
4231a819 918 if Progressor._ProgressThread is not None:\r
f51461c8
LG
919 Progressor._ProgressThread.join()\r
920 Progressor._ProgressThread = None\r
921\r
922## A dict which can access its keys and/or values orderly\r
923#\r
924# The class implements a new kind of dict which its keys or values can be\r
925# accessed in the order they are added into the dict. It guarantees the order\r
926# by making use of an internal list to keep a copy of keys.\r
927#\r
928class sdict(IterableUserDict):\r
929 ## Constructor\r
930 def __init__(self):\r
931 IterableUserDict.__init__(self)\r
932 self._key_list = []\r
933\r
934 ## [] operator\r
935 def __setitem__(self, key, value):\r
936 if key not in self._key_list:\r
937 self._key_list.append(key)\r
938 IterableUserDict.__setitem__(self, key, value)\r
939\r
940 ## del operator\r
941 def __delitem__(self, key):\r
942 self._key_list.remove(key)\r
943 IterableUserDict.__delitem__(self, key)\r
944\r
945 ## used in "for k in dict" loop to ensure the correct order\r
946 def __iter__(self):\r
947 return self.iterkeys()\r
948\r
949 ## len() support\r
950 def __len__(self):\r
951 return len(self._key_list)\r
952\r
953 ## "in" test support\r
954 def __contains__(self, key):\r
955 return key in self._key_list\r
956\r
957 ## indexof support\r
958 def index(self, key):\r
959 return self._key_list.index(key)\r
960\r
961 ## insert support\r
962 def insert(self, key, newkey, newvalue, order):\r
963 index = self._key_list.index(key)\r
964 if order == 'BEFORE':\r
965 self._key_list.insert(index, newkey)\r
966 IterableUserDict.__setitem__(self, newkey, newvalue)\r
967 elif order == 'AFTER':\r
968 self._key_list.insert(index + 1, newkey)\r
969 IterableUserDict.__setitem__(self, newkey, newvalue)\r
970\r
971 ## append support\r
972 def append(self, sdict):\r
973 for key in sdict:\r
974 if key not in self._key_list:\r
975 self._key_list.append(key)\r
976 IterableUserDict.__setitem__(self, key, sdict[key])\r
977\r
978 def has_key(self, key):\r
979 return key in self._key_list\r
980\r
981 ## Empty the dict\r
982 def clear(self):\r
983 self._key_list = []\r
984 IterableUserDict.clear(self)\r
985\r
986 ## Return a copy of keys\r
987 def keys(self):\r
988 keys = []\r
989 for key in self._key_list:\r
990 keys.append(key)\r
991 return keys\r
992\r
993 ## Return a copy of values\r
994 def values(self):\r
995 values = []\r
996 for key in self._key_list:\r
997 values.append(self[key])\r
998 return values\r
999\r
1000 ## Return a copy of (key, value) list\r
1001 def items(self):\r
1002 items = []\r
1003 for key in self._key_list:\r
1004 items.append((key, self[key]))\r
1005 return items\r
1006\r
1007 ## Iteration support\r
1008 def iteritems(self):\r
1009 return iter(self.items())\r
1010\r
1011 ## Keys interation support\r
1012 def iterkeys(self):\r
1013 return iter(self.keys())\r
1014\r
1015 ## Values interation support\r
1016 def itervalues(self):\r
1017 return iter(self.values())\r
1018\r
1019 ## Return value related to a key, and remove the (key, value) from the dict\r
1020 def pop(self, key, *dv):\r
1021 value = None\r
1022 if key in self._key_list:\r
1023 value = self[key]\r
1024 self.__delitem__(key)\r
1025 elif len(dv) != 0 :\r
1026 value = kv[0]\r
1027 return value\r
1028\r
1029 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1030 def popitem(self):\r
1031 key = self._key_list[-1]\r
1032 value = self[key]\r
1033 self.__delitem__(key)\r
1034 return key, value\r
1035\r
1036 def update(self, dict=None, **kwargs):\r
4231a819 1037 if dict is not None:\r
f51461c8
LG
1038 for k, v in dict.items():\r
1039 self[k] = v\r
1040 if len(kwargs):\r
1041 for k, v in kwargs.items():\r
1042 self[k] = v\r
1043\r
1044## Dictionary with restricted keys\r
1045#\r
1046class rdict(dict):\r
1047 ## Constructor\r
1048 def __init__(self, KeyList):\r
1049 for Key in KeyList:\r
1050 dict.__setitem__(self, Key, "")\r
1051\r
1052 ## []= operator\r
1053 def __setitem__(self, key, value):\r
1054 if key not in self:\r
1055 EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key,\r
1056 ExtraData=", ".join(dict.keys(self)))\r
1057 dict.__setitem__(self, key, value)\r
1058\r
1059 ## =[] operator\r
1060 def __getitem__(self, key):\r
1061 if key not in self:\r
1062 return ""\r
1063 return dict.__getitem__(self, key)\r
1064\r
1065 ## del operator\r
1066 def __delitem__(self, key):\r
1067 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")\r
1068\r
1069 ## Empty the dict\r
1070 def clear(self):\r
1071 for Key in self:\r
1072 self.__setitem__(Key, "")\r
1073\r
1074 ## Return value related to a key, and remove the (key, value) from the dict\r
1075 def pop(self, key, *dv):\r
1076 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")\r
1077\r
1078 ## Return (key, value) pair, and remove the (key, value) from the dict\r
1079 def popitem(self):\r
1080 EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")\r
1081\r
1082## Dictionary using prioritized list as key\r
1083#\r
1084class tdict:\r
1085 _ListType = type([])\r
1086 _TupleType = type(())\r
1087 _Wildcard = 'COMMON'\r
1088 _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']\r
1089\r
1090 def __init__(self, _Single_=False, _Level_=2):\r
1091 self._Level_ = _Level_\r
1092 self.data = {}\r
1093 self._Single_ = _Single_\r
1094\r
1095 # =[] operator\r
1096 def __getitem__(self, key):\r
1097 KeyType = type(key)\r
1098 RestKeys = None\r
1099 if KeyType == self._ListType or KeyType == self._TupleType:\r
1100 FirstKey = key[0]\r
1101 if len(key) > 1:\r
1102 RestKeys = key[1:]\r
1103 elif self._Level_ > 1:\r
47fea6af 1104 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1105 else:\r
1106 FirstKey = key\r
1107 if self._Level_ > 1:\r
47fea6af 1108 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8 1109\r
4231a819 1110 if FirstKey is None or str(FirstKey).upper() in self._ValidWildcardList:\r
f51461c8
LG
1111 FirstKey = self._Wildcard\r
1112\r
1113 if self._Single_:\r
1114 return self._GetSingleValue(FirstKey, RestKeys)\r
1115 else:\r
1116 return self._GetAllValues(FirstKey, RestKeys)\r
1117\r
1118 def _GetSingleValue(self, FirstKey, RestKeys):\r
1119 Value = None\r
1120 #print "%s-%s" % (FirstKey, self._Level_) ,\r
1121 if self._Level_ > 1:\r
1122 if FirstKey == self._Wildcard:\r
1123 if FirstKey in self.data:\r
1124 Value = self.data[FirstKey][RestKeys]\r
4231a819 1125 if Value is None:\r
f51461c8
LG
1126 for Key in self.data:\r
1127 Value = self.data[Key][RestKeys]\r
4231a819 1128 if Value is not None: break\r
f51461c8
LG
1129 else:\r
1130 if FirstKey in self.data:\r
1131 Value = self.data[FirstKey][RestKeys]\r
4231a819 1132 if Value is None and self._Wildcard in self.data:\r
f51461c8
LG
1133 #print "Value=None"\r
1134 Value = self.data[self._Wildcard][RestKeys]\r
1135 else:\r
1136 if FirstKey == self._Wildcard:\r
1137 if FirstKey in self.data:\r
1138 Value = self.data[FirstKey]\r
4231a819 1139 if Value is None:\r
f51461c8
LG
1140 for Key in self.data:\r
1141 Value = self.data[Key]\r
4231a819 1142 if Value is not None: break\r
f51461c8
LG
1143 else:\r
1144 if FirstKey in self.data:\r
1145 Value = self.data[FirstKey]\r
1146 elif self._Wildcard in self.data:\r
1147 Value = self.data[self._Wildcard]\r
1148 return Value\r
1149\r
1150 def _GetAllValues(self, FirstKey, RestKeys):\r
1151 Value = []\r
1152 if self._Level_ > 1:\r
1153 if FirstKey == self._Wildcard:\r
1154 for Key in self.data:\r
1155 Value += self.data[Key][RestKeys]\r
1156 else:\r
1157 if FirstKey in self.data:\r
1158 Value += self.data[FirstKey][RestKeys]\r
1159 if self._Wildcard in self.data:\r
1160 Value += self.data[self._Wildcard][RestKeys]\r
1161 else:\r
1162 if FirstKey == self._Wildcard:\r
1163 for Key in self.data:\r
1164 Value.append(self.data[Key])\r
1165 else:\r
1166 if FirstKey in self.data:\r
1167 Value.append(self.data[FirstKey])\r
1168 if self._Wildcard in self.data:\r
1169 Value.append(self.data[self._Wildcard])\r
1170 return Value\r
1171\r
1172 ## []= operator\r
1173 def __setitem__(self, key, value):\r
1174 KeyType = type(key)\r
1175 RestKeys = None\r
1176 if KeyType == self._ListType or KeyType == self._TupleType:\r
1177 FirstKey = key[0]\r
1178 if len(key) > 1:\r
1179 RestKeys = key[1:]\r
1180 else:\r
47fea6af 1181 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1182 else:\r
1183 FirstKey = key\r
1184 if self._Level_ > 1:\r
47fea6af 1185 RestKeys = [self._Wildcard for i in range(0, self._Level_ - 1)]\r
f51461c8
LG
1186\r
1187 if FirstKey in self._ValidWildcardList:\r
1188 FirstKey = self._Wildcard\r
1189\r
1190 if FirstKey not in self.data and self._Level_ > 0:\r
1191 self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
1192\r
1193 if self._Level_ > 1:\r
1194 self.data[FirstKey][RestKeys] = value\r
1195 else:\r
1196 self.data[FirstKey] = value\r
1197\r
1198 def SetGreedyMode(self):\r
1199 self._Single_ = False\r
1200 if self._Level_ > 1:\r
1201 for Key in self.data:\r
1202 self.data[Key].SetGreedyMode()\r
1203\r
1204 def SetSingleMode(self):\r
1205 self._Single_ = True\r
1206 if self._Level_ > 1:\r
1207 for Key in self.data:\r
1208 self.data[Key].SetSingleMode()\r
1209\r
1210 def GetKeys(self, KeyIndex=0):\r
1211 assert KeyIndex >= 0\r
1212 if KeyIndex == 0:\r
1213 return set(self.data.keys())\r
1214 else:\r
1215 keys = set()\r
1216 for Key in self.data:\r
1217 keys |= self.data[Key].GetKeys(KeyIndex - 1)\r
1218 return keys\r
1219\r
8565b582
YZ
1220def IsFieldValueAnArray (Value):\r
1221 Value = Value.strip()\r
91fa33ee 1222 if Value.startswith(TAB_GUID) and Value.endswith(')'):\r
8565b582
YZ
1223 return True\r
1224 if Value.startswith('L"') and Value.endswith('"') and len(list(Value[2:-1])) > 1:\r
1225 return True\r
1226 if Value[0] == '"' and Value[-1] == '"' and len(list(Value[1:-1])) > 1:\r
1227 return True\r
1228 if Value[0] == '{' and Value[-1] == '}':\r
1229 return True\r
1230 if Value.startswith("L'") and Value.endswith("'") and len(list(Value[2:-1])) > 1:\r
1231 return True\r
1232 if Value[0] == "'" and Value[-1] == "'" and len(list(Value[1:-1])) > 1:\r
1233 return True\r
1234 return False\r
1235\r
67e11e4d 1236def AnalyzePcdExpression(Setting):\r
f51461c8 1237 Setting = Setting.strip()\r
ea927d2f
FY
1238 # There might be escaped quote in a string: \", \\\" , \', \\\'\r
1239 Data = Setting\r
f51461c8
LG
1240 # There might be '|' in string and in ( ... | ... ), replace it with '-'\r
1241 NewStr = ''\r
ea927d2f
FY
1242 InSingleQuoteStr = False\r
1243 InDoubleQuoteStr = False\r
f51461c8 1244 Pair = 0\r
ea927d2f
FY
1245 for Index, ch in enumerate(Data):\r
1246 if ch == '"' and not InSingleQuoteStr:\r
1247 if Data[Index - 1] != '\\':\r
1248 InDoubleQuoteStr = not InDoubleQuoteStr\r
1249 elif ch == "'" and not InDoubleQuoteStr:\r
1250 if Data[Index - 1] != '\\':\r
1251 InSingleQuoteStr = not InSingleQuoteStr\r
1252 elif ch == '(' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 1253 Pair += 1\r
ea927d2f 1254 elif ch == ')' and not (InSingleQuoteStr or InDoubleQuoteStr):\r
f51461c8 1255 Pair -= 1\r
47fea6af 1256\r
ea927d2f 1257 if (Pair > 0 or InSingleQuoteStr or InDoubleQuoteStr) and ch == TAB_VALUE_SPLIT:\r
f51461c8
LG
1258 NewStr += '-'\r
1259 else:\r
1260 NewStr += ch\r
1261 FieldList = []\r
1262 StartPos = 0\r
1263 while True:\r
1264 Pos = NewStr.find(TAB_VALUE_SPLIT, StartPos)\r
1265 if Pos < 0:\r
1266 FieldList.append(Setting[StartPos:].strip())\r
1267 break\r
1268 FieldList.append(Setting[StartPos:Pos].strip())\r
1269 StartPos = Pos + 1\r
1270\r
67e11e4d
YZ
1271 return FieldList\r
1272\r
726c501c 1273def ParseDevPathValue (Value):\r
7dbc50bd
YZ
1274 if '\\' in Value:\r
1275 Value.replace('\\', '/').replace(' ', '')\r
7dbc50bd
YZ
1276\r
1277 Cmd = 'DevicePath ' + '"' + Value + '"'\r
1278 try:\r
1279 p = subprocess.Popen(Cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)\r
1280 out, err = p.communicate()\r
5b0671c1 1281 except Exception as X:\r
7dbc50bd
YZ
1282 raise BadExpression("DevicePath: %s" % (str(X)) )\r
1283 finally:\r
1284 subprocess._cleanup()\r
1285 p.stdout.close()\r
1286 p.stderr.close()\r
1287 if err:\r
1288 raise BadExpression("DevicePath: %s" % str(err))\r
1289 Size = len(out.split())\r
1290 out = ','.join(out.split())\r
1291 return '{' + out + '}', Size\r
726c501c 1292\r
ae7b6df8 1293def ParseFieldValue (Value):\r
726c501c
YZ
1294 if type(Value) == type(0):\r
1295 return Value, (Value.bit_length() + 7) / 8\r
87d2afd0 1296 if type(Value) != type(''):\r
726c501c
YZ
1297 raise BadExpression('Type %s is %s' %(Value, type(Value)))\r
1298 Value = Value.strip()\r
656d2539 1299 if Value.startswith(TAB_UINT8) and Value.endswith(')'):\r
726c501c
YZ
1300 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1301 if Size > 1:\r
1302 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1303 return Value, 1\r
656d2539 1304 if Value.startswith(TAB_UINT16) and Value.endswith(')'):\r
726c501c
YZ
1305 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1306 if Size > 2:\r
1307 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1308 return Value, 2\r
656d2539 1309 if Value.startswith(TAB_UINT32) and Value.endswith(')'):\r
726c501c
YZ
1310 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1311 if Size > 4:\r
1312 raise BadExpression('Value (%s) Size larger than %d' %(Value, Size))\r
1313 return Value, 4\r
656d2539 1314 if Value.startswith(TAB_UINT64) and Value.endswith(')'):\r
726c501c
YZ
1315 Value, Size = ParseFieldValue(Value.split('(', 1)[1][:-1])\r
1316 if Size > 8:\r
1317 raise BadExpression('Value (%s) Size larger than %d' % (Value, Size))\r
1318 return Value, 8\r
91fa33ee 1319 if Value.startswith(TAB_GUID) and Value.endswith(')'):\r
726c501c
YZ
1320 Value = Value.split('(', 1)[1][:-1].strip()\r
1321 if Value[0] == '{' and Value[-1] == '}':\r
4344a788
FY
1322 TmpValue = GuidStructureStringToGuidString(Value)\r
1323 if len(TmpValue) == 0:\r
1324 raise BadExpression("Invalid GUID value string %s" % Value)\r
1325 Value = TmpValue\r
726c501c
YZ
1326 if Value[0] == '"' and Value[-1] == '"':\r
1327 Value = Value[1:-1]\r
1328 try:\r
1329 Value = "'" + uuid.UUID(Value).get_bytes_le() + "'"\r
5b0671c1 1330 except ValueError as Message:\r
caf74495 1331 raise BadExpression(Message)\r
726c501c
YZ
1332 Value, Size = ParseFieldValue(Value)\r
1333 return Value, 16\r
1334 if Value.startswith('L"') and Value.endswith('"'):\r
1335 # Unicode String\r
4faf1322
FY
1336 # translate escape character\r
1337 Value = Value[1:]\r
1338 try:\r
1339 Value = eval(Value)\r
1340 except:\r
1341 Value = Value[1:-1]\r
1342 List = list(Value)\r
726c501c
YZ
1343 List.reverse()\r
1344 Value = 0\r
1345 for Char in List:\r
1346 Value = (Value << 16) | ord(Char)\r
1347 return Value, (len(List) + 1) * 2\r
1348 if Value.startswith('"') and Value.endswith('"'):\r
1349 # ASCII String\r
4faf1322
FY
1350 # translate escape character\r
1351 try:\r
1352 Value = eval(Value)\r
1353 except:\r
1354 Value = Value[1:-1]\r
1355 List = list(Value)\r
726c501c
YZ
1356 List.reverse()\r
1357 Value = 0\r
1358 for Char in List:\r
1359 Value = (Value << 8) | ord(Char)\r
1360 return Value, len(List) + 1\r
1361 if Value.startswith("L'") and Value.endswith("'"):\r
1362 # Unicode Character Constant\r
4faf1322
FY
1363 # translate escape character\r
1364 Value = Value[1:]\r
1365 try:\r
1366 Value = eval(Value)\r
1367 except:\r
1368 Value = Value[1:-1]\r
1369 List = list(Value)\r
0e6b8673
FY
1370 if len(List) == 0:\r
1371 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1372 List.reverse()\r
1373 Value = 0\r
1374 for Char in List:\r
1375 Value = (Value << 16) | ord(Char)\r
1376 return Value, len(List) * 2\r
1377 if Value.startswith("'") and Value.endswith("'"):\r
1378 # Character constant\r
4faf1322
FY
1379 # translate escape character\r
1380 try:\r
1381 Value = eval(Value)\r
1382 except:\r
1383 Value = Value[1:-1]\r
1384 List = list(Value)\r
0e6b8673
FY
1385 if len(List) == 0:\r
1386 raise BadExpression('Length %s is %s' % (Value, len(List)))\r
726c501c
YZ
1387 List.reverse()\r
1388 Value = 0\r
1389 for Char in List:\r
1390 Value = (Value << 8) | ord(Char)\r
1391 return Value, len(List)\r
1392 if Value.startswith('{') and Value.endswith('}'):\r
1393 # Byte array\r
1394 Value = Value[1:-1]\r
1395 List = [Item.strip() for Item in Value.split(',')]\r
1396 List.reverse()\r
1397 Value = 0\r
1398 RetSize = 0\r
1399 for Item in List:\r
1400 ItemValue, Size = ParseFieldValue(Item)\r
1401 RetSize += Size\r
1402 for I in range(Size):\r
1403 Value = (Value << 8) | ((ItemValue >> 8 * I) & 0xff)\r
1404 return Value, RetSize\r
1405 if Value.startswith('DEVICE_PATH(') and Value.endswith(')'):\r
8ad5f10a
FY
1406 Value = Value.replace("DEVICE_PATH(", '').rstrip(')')\r
1407 Value = Value.strip().strip('"')\r
726c501c
YZ
1408 return ParseDevPathValue(Value)\r
1409 if Value.lower().startswith('0x'):\r
1410 Value = int(Value, 16)\r
1411 if Value == 0:\r
1412 return 0, 1\r
1413 return Value, (Value.bit_length() + 7) / 8\r
1414 if Value[0].isdigit():\r
1415 Value = int(Value, 10)\r
1416 if Value == 0:\r
1417 return 0, 1\r
1418 return Value, (Value.bit_length() + 7) / 8\r
1419 if Value.lower() == 'true':\r
1420 return 1, 1\r
1421 if Value.lower() == 'false':\r
1422 return 0, 1\r
ae7b6df8 1423 return Value, 1\r
ae7b6df8 1424\r
67e11e4d
YZ
1425## AnalyzeDscPcd\r
1426#\r
1427# Analyze DSC PCD value, since there is no data type info in DSC\r
ab0ff0b0 1428# This fuction is used to match functions (AnalyzePcdData) used for retrieving PCD value from database\r
67e11e4d
YZ
1429# 1. Feature flag: TokenSpace.PcdCName|PcdValue\r
1430# 2. Fix and Patch:TokenSpace.PcdCName|PcdValue[|MaxSize]\r
1431# 3. Dynamic default:\r
1432# TokenSpace.PcdCName|PcdValue[|VOID*[|MaxSize]]\r
1433# TokenSpace.PcdCName|PcdValue\r
1434# 4. Dynamic VPD:\r
1435# TokenSpace.PcdCName|VpdOffset[|VpdValue]\r
1436# TokenSpace.PcdCName|VpdOffset[|MaxSize[|VpdValue]]\r
1437# 5. Dynamic HII:\r
1438# TokenSpace.PcdCName|HiiString|VaiableGuid|VariableOffset[|HiiValue]\r
1439# PCD value needs to be located in such kind of string, and the PCD value might be an expression in which\r
1440# there might have "|" operator, also in string value.\r
1441#\r
1442# @param Setting: String contain information described above with "TokenSpace.PcdCName|" stripped\r
1443# @param PcdType: PCD type: feature, fixed, dynamic default VPD HII\r
1444# @param DataType: The datum type of PCD: VOID*, UNIT, BOOL\r
1445# @retval:\r
1446# ValueList: A List contain fields described above\r
1447# IsValid: True if conforming EBNF, otherwise False\r
1448# Index: The index where PcdValue is in ValueList\r
1449#\r
1450def AnalyzeDscPcd(Setting, PcdType, DataType=''):\r
1451 FieldList = AnalyzePcdExpression(Setting)\r
1452\r
f51461c8
LG
1453 IsValid = True\r
1454 if PcdType in (MODEL_PCD_FIXED_AT_BUILD, MODEL_PCD_PATCHABLE_IN_MODULE, MODEL_PCD_FEATURE_FLAG):\r
1455 Value = FieldList[0]\r
1456 Size = ''\r
1457 if len(FieldList) > 1:\r
ae7b6df8 1458 if FieldList[1].upper().startswith("0X") or FieldList[1].isdigit():\r
f51461c8 1459 Size = FieldList[1]\r
ae7b6df8
LG
1460 else:\r
1461 DataType = FieldList[1]\r
1462\r
f51461c8
LG
1463 if len(FieldList) > 2:\r
1464 Size = FieldList[2]\r
ae7b6df8 1465 if DataType == "":\r
f51461c8 1466 IsValid = (len(FieldList) <= 1)\r
ae7b6df8
LG
1467 else:\r
1468 IsValid = (len(FieldList) <= 3)\r
1469# Value, Size = ParseFieldValue(Value)\r
520365de
B
1470 if Size:\r
1471 try:\r
1472 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1473 except:\r
1474 IsValid = False\r
1475 Size = -1\r
ae7b6df8 1476 return [str(Value), '', str(Size)], IsValid, 0\r
f51461c8
LG
1477 elif PcdType in (MODEL_PCD_DYNAMIC_DEFAULT, MODEL_PCD_DYNAMIC_EX_DEFAULT):\r
1478 Value = FieldList[0]\r
1479 Size = Type = ''\r
1480 if len(FieldList) > 1:\r
1481 Type = FieldList[1]\r
1482 else:\r
1483 Type = DataType\r
1484 if len(FieldList) > 2:\r
1485 Size = FieldList[2]\r
ae7b6df8 1486 if DataType == "":\r
f51461c8 1487 IsValid = (len(FieldList) <= 1)\r
ae7b6df8
LG
1488 else:\r
1489 IsValid = (len(FieldList) <= 3)\r
520365de
B
1490\r
1491 if Size:\r
1492 try:\r
1493 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1494 except:\r
1495 IsValid = False\r
1496 Size = -1\r
1497 return [Value, Type, str(Size)], IsValid, 0\r
f51461c8
LG
1498 elif PcdType in (MODEL_PCD_DYNAMIC_VPD, MODEL_PCD_DYNAMIC_EX_VPD):\r
1499 VpdOffset = FieldList[0]\r
1500 Value = Size = ''\r
656d2539 1501 if not DataType == TAB_VOID:\r
f51461c8
LG
1502 if len(FieldList) > 1:\r
1503 Value = FieldList[1]\r
1504 else:\r
1505 if len(FieldList) > 1:\r
1506 Size = FieldList[1]\r
1507 if len(FieldList) > 2:\r
1508 Value = FieldList[2]\r
ae7b6df8
LG
1509 if DataType == "":\r
1510 IsValid = (len(FieldList) <= 1)\r
f51461c8 1511 else:\r
ae7b6df8 1512 IsValid = (len(FieldList) <= 3)\r
520365de
B
1513 if Size:\r
1514 try:\r
1515 int(Size,16) if Size.upper().startswith("0X") else int(Size)\r
1516 except:\r
1517 IsValid = False\r
1518 Size = -1\r
1519 return [VpdOffset, str(Size), Value], IsValid, 2\r
f51461c8
LG
1520 elif PcdType in (MODEL_PCD_DYNAMIC_HII, MODEL_PCD_DYNAMIC_EX_HII):\r
1521 HiiString = FieldList[0]\r
82a6a960 1522 Guid = Offset = Value = Attribute = ''\r
f51461c8
LG
1523 if len(FieldList) > 1:\r
1524 Guid = FieldList[1]\r
1525 if len(FieldList) > 2:\r
1526 Offset = FieldList[2]\r
1527 if len(FieldList) > 3:\r
1528 Value = FieldList[3]\r
82a6a960
BF
1529 if len(FieldList) > 4:\r
1530 Attribute = FieldList[4]\r
1531 IsValid = (3 <= len(FieldList) <= 5)\r
1532 return [HiiString, Guid, Offset, Value, Attribute], IsValid, 3\r
f51461c8
LG
1533 return [], False, 0\r
1534\r
1535## AnalyzePcdData\r
1536#\r
1537# Analyze the pcd Value, Datum type and TokenNumber.\r
1538# Used to avoid split issue while the value string contain "|" character\r
1539#\r
1540# @param[in] Setting: A String contain value/datum type/token number information;\r
1541# \r
1542# @retval ValueList: A List contain value, datum type and toke number. \r
1543#\r
47fea6af
YZ
1544def AnalyzePcdData(Setting):\r
1545 ValueList = ['', '', '']\r
1546\r
1547 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')\r
f51461c8
LG
1548 PtrValue = ValueRe.findall(Setting)\r
1549 \r
1550 ValueUpdateFlag = False\r
1551 \r
1552 if len(PtrValue) >= 1:\r
1553 Setting = re.sub(ValueRe, '', Setting)\r
47fea6af 1554 ValueUpdateFlag = True\r
f51461c8
LG
1555\r
1556 TokenList = Setting.split(TAB_VALUE_SPLIT)\r
1557 ValueList[0:len(TokenList)] = TokenList\r
1558 \r
1559 if ValueUpdateFlag:\r
1560 ValueList[0] = PtrValue[0]\r
1561 \r
1562 return ValueList \r
1563 \r
f51461c8
LG
1564## check format of PCD value against its the datum type\r
1565#\r
1566# For PCD value setting\r
1567#\r
1568def CheckPcdDatum(Type, Value):\r
656d2539 1569 if Type == TAB_VOID:\r
47fea6af 1570 ValueRe = re.compile(r'\s*L?\".*\"\s*$')\r
f51461c8 1571 if not (((Value.startswith('L"') or Value.startswith('"')) and Value.endswith('"'))\r
d5988a8a 1572 or (Value.startswith('{') and Value.endswith('}')) or (Value.startswith("L'") or Value.startswith("'") and Value.endswith("'"))\r
f51461c8
LG
1573 ):\r
1574 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\\r
d5988a8a 1575 ", \"...\" or \'...\' for string, L\"...\" or L\'...\' for unicode string" % (Value, Type)\r
f51461c8
LG
1576 elif ValueRe.match(Value):\r
1577 # Check the chars in UnicodeString or CString is printable\r
1578 if Value.startswith("L"):\r
1579 Value = Value[2:-1]\r
1580 else:\r
1581 Value = Value[1:-1]\r
1582 Printset = set(string.printable)\r
1583 Printset.remove(TAB_PRINTCHAR_VT)\r
1584 Printset.add(TAB_PRINTCHAR_BS)\r
1585 Printset.add(TAB_PRINTCHAR_NUL)\r
1586 if not set(Value).issubset(Printset):\r
1587 PrintList = list(Printset)\r
1588 PrintList.sort()\r
1589 return False, "Invalid PCD string value of type [%s]; must be printable chars %s." % (Type, PrintList)\r
1590 elif Type == 'BOOLEAN':\r
1591 if Value not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:\r
1592 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\\r
1593 ", FALSE, False, false, 0x0, 0x00, 0" % (Value, Type)\r
1594 elif Type in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64]:\r
1595 try:\r
1596 Value = long(Value, 0)\r
1597 except:\r
1598 return False, "Invalid value [%s] of type [%s];"\\r
1599 " must be a hexadecimal, decimal or octal in C language format." % (Value, Type)\r
1600 else:\r
ae7b6df8 1601 return True, "StructurePcd"\r
f51461c8
LG
1602\r
1603 return True, ""\r
1604\r
1605## Split command line option string to list\r
1606#\r
1607# subprocess.Popen needs the args to be a sequence. Otherwise there's problem\r
1608# in non-windows platform to launch command\r
1609#\r
1610def SplitOption(OptionString):\r
1611 OptionList = []\r
1612 LastChar = " "\r
1613 OptionStart = 0\r
1614 QuotationMark = ""\r
1615 for Index in range(0, len(OptionString)):\r
1616 CurrentChar = OptionString[Index]\r
1617 if CurrentChar in ['"', "'"]:\r
1618 if QuotationMark == CurrentChar:\r
1619 QuotationMark = ""\r
1620 elif QuotationMark == "":\r
1621 QuotationMark = CurrentChar\r
1622 continue\r
1623 elif QuotationMark:\r
1624 continue\r
1625\r
1626 if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:\r
1627 if Index > OptionStart:\r
47fea6af 1628 OptionList.append(OptionString[OptionStart:Index - 1])\r
f51461c8
LG
1629 OptionStart = Index\r
1630 LastChar = CurrentChar\r
1631 OptionList.append(OptionString[OptionStart:])\r
1632 return OptionList\r
1633\r
1634def CommonPath(PathList):\r
1635 P1 = min(PathList).split(os.path.sep)\r
1636 P2 = max(PathList).split(os.path.sep)\r
1637 for Index in xrange(min(len(P1), len(P2))):\r
1638 if P1[Index] != P2[Index]:\r
1639 return os.path.sep.join(P1[:Index])\r
1640 return os.path.sep.join(P1)\r
1641\r
97fa0ee9
YL
1642#\r
1643# Convert string to C format array\r
1644#\r
1645def ConvertStringToByteArray(Value):\r
1646 Value = Value.strip()\r
1647 if not Value:\r
1648 return None\r
1649 if Value[0] == '{':\r
1650 if not Value.endswith('}'):\r
1651 return None\r
1652 Value = Value.replace(' ', '').replace('{', '').replace('}', '')\r
1653 ValFields = Value.split(',')\r
1654 try:\r
1655 for Index in range(len(ValFields)):\r
1656 ValFields[Index] = str(int(ValFields[Index], 0))\r
1657 except ValueError:\r
1658 return None\r
1659 Value = '{' + ','.join(ValFields) + '}'\r
1660 return Value\r
1661\r
1662 Unicode = False\r
1663 if Value.startswith('L"'):\r
1664 if not Value.endswith('"'):\r
1665 return None\r
1666 Value = Value[1:]\r
1667 Unicode = True\r
1668 elif not Value.startswith('"') or not Value.endswith('"'):\r
1669 return None\r
1670\r
1671 Value = eval(Value) # translate escape character\r
1672 NewValue = '{'\r
1673 for Index in range(0,len(Value)):\r
1674 if Unicode:\r
1675 NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','\r
1676 else:\r
1677 NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','\r
1678 Value = NewValue + '0}'\r
1679 return Value\r
1680\r
f51461c8
LG
1681class PathClass(object):\r
1682 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,\r
1683 Arch='COMMON', ToolChainFamily='', Target='', TagName='', ToolCode=''):\r
1684 self.Arch = Arch\r
1685 self.File = str(File)\r
1686 if os.path.isabs(self.File):\r
1687 self.Root = ''\r
1688 self.AlterRoot = ''\r
1689 else:\r
1690 self.Root = str(Root)\r
1691 self.AlterRoot = str(AlterRoot)\r
1692\r
1693 # Remove any '.' and '..' in path\r
1694 if self.Root:\r
05cc51ad 1695 self.Root = mws.getWs(self.Root, self.File)\r
f51461c8
LG
1696 self.Path = os.path.normpath(os.path.join(self.Root, self.File))\r
1697 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))\r
1698 # eliminate the side-effect of 'C:'\r
1699 if self.Root[-1] == ':':\r
1700 self.Root += os.path.sep\r
1701 # file path should not start with path separator\r
1702 if self.Root[-1] == os.path.sep:\r
1703 self.File = self.Path[len(self.Root):]\r
1704 else:\r
47fea6af 1705 self.File = self.Path[len(self.Root) + 1:]\r
f51461c8
LG
1706 else:\r
1707 self.Path = os.path.normpath(self.File)\r
1708\r
1709 self.SubDir, self.Name = os.path.split(self.File)\r
1710 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1711\r
1712 if self.Root:\r
1713 if self.SubDir:\r
1714 self.Dir = os.path.join(self.Root, self.SubDir)\r
1715 else:\r
1716 self.Dir = self.Root\r
1717 else:\r
1718 self.Dir = self.SubDir\r
1719\r
1720 if IsBinary:\r
1721 self.Type = Type\r
1722 else:\r
1723 self.Type = self.Ext.lower()\r
1724\r
1725 self.IsBinary = IsBinary\r
1726 self.Target = Target\r
1727 self.TagName = TagName\r
1728 self.ToolCode = ToolCode\r
1729 self.ToolChainFamily = ToolChainFamily\r
1730\r
1731 self._Key = None\r
1732\r
1733 ## Convert the object of this class to a string\r
1734 #\r
1735 # Convert member Path of the class to a string\r
1736 #\r
1737 # @retval string Formatted String\r
1738 #\r
1739 def __str__(self):\r
1740 return self.Path\r
1741\r
1742 ## Override __eq__ function\r
1743 #\r
1744 # Check whether PathClass are the same\r
1745 #\r
1746 # @retval False The two PathClass are different\r
1747 # @retval True The two PathClass are the same\r
1748 #\r
1749 def __eq__(self, Other):\r
1750 if type(Other) == type(self):\r
1751 return self.Path == Other.Path\r
1752 else:\r
1753 return self.Path == str(Other)\r
1754\r
1755 ## Override __cmp__ function\r
1756 #\r
1757 # Customize the comparsion operation of two PathClass\r
1758 #\r
1759 # @retval 0 The two PathClass are different\r
1760 # @retval -1 The first PathClass is less than the second PathClass\r
1761 # @retval 1 The first PathClass is Bigger than the second PathClass\r
1762 def __cmp__(self, Other):\r
1763 if type(Other) == type(self):\r
1764 OtherKey = Other.Path\r
1765 else:\r
1766 OtherKey = str(Other)\r
1767 \r
1768 SelfKey = self.Path\r
1769 if SelfKey == OtherKey:\r
1770 return 0\r
1771 elif SelfKey > OtherKey:\r
1772 return 1\r
1773 else:\r
1774 return -1\r
1775\r
1776 ## Override __hash__ function\r
1777 #\r
1778 # Use Path as key in hash table\r
1779 #\r
1780 # @retval string Key for hash table\r
1781 #\r
1782 def __hash__(self):\r
1783 return hash(self.Path)\r
1784\r
1785 def _GetFileKey(self):\r
4231a819 1786 if self._Key is None:\r
f51461c8
LG
1787 self._Key = self.Path.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target\r
1788 return self._Key\r
1789\r
1790 def _GetTimeStamp(self):\r
1791 return os.stat(self.Path)[8]\r
1792\r
1793 def Validate(self, Type='', CaseSensitive=True):\r
1794 if GlobalData.gCaseInsensitive:\r
1795 CaseSensitive = False\r
1796 if Type and Type.lower() != self.Type:\r
1797 return FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % (self.File, Type, self.Type)\r
1798\r
1799 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)\r
1800 if not RealRoot and not RealFile:\r
1801 RealFile = self.File\r
1802 if self.AlterRoot:\r
1803 RealFile = os.path.join(self.AlterRoot, self.File)\r
1804 elif self.Root:\r
1805 RealFile = os.path.join(self.Root, self.File)\r
05cc51ad
LY
1806 if len (mws.getPkgPath()) == 0:\r
1807 return FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)\r
1808 else:\r
1809 return FILE_NOT_FOUND, "%s is not found in packages path:\n\t%s" % (self.File, '\n\t'.join(mws.getPkgPath()))\r
f51461c8
LG
1810\r
1811 ErrorCode = 0\r
1812 ErrorInfo = ''\r
1813 if RealRoot != self.Root or RealFile != self.File:\r
1814 if CaseSensitive and (RealFile != self.File or (RealRoot != self.Root and RealRoot != self.AlterRoot)):\r
1815 ErrorCode = FILE_CASE_MISMATCH\r
1816 ErrorInfo = self.File + '\n\t' + RealFile + " [in file system]"\r
1817\r
1818 self.SubDir, self.Name = os.path.split(RealFile)\r
1819 self.BaseName, self.Ext = os.path.splitext(self.Name)\r
1820 if self.SubDir:\r
1821 self.Dir = os.path.join(RealRoot, self.SubDir)\r
1822 else:\r
1823 self.Dir = RealRoot\r
1824 self.File = RealFile\r
1825 self.Root = RealRoot\r
1826 self.Path = os.path.join(RealRoot, RealFile)\r
1827 return ErrorCode, ErrorInfo\r
1828\r
1829 Key = property(_GetFileKey)\r
1830 TimeStamp = property(_GetTimeStamp)\r
1831\r
1832## Parse PE image to get the required PE informaion.\r
1833#\r
1834class PeImageClass():\r
1835 ## Constructor\r
1836 #\r
1837 # @param File FilePath of PeImage\r
1838 #\r
1839 def __init__(self, PeFile):\r
1840 self.FileName = PeFile\r
1841 self.IsValid = False\r
1842 self.Size = 0\r
1843 self.EntryPoint = 0\r
1844 self.SectionAlignment = 0\r
1845 self.SectionHeaderList = []\r
1846 self.ErrorInfo = ''\r
1847 try:\r
1848 PeObject = open(PeFile, 'rb')\r
1849 except:\r
1850 self.ErrorInfo = self.FileName + ' can not be found\n'\r
1851 return\r
1852 # Read DOS header\r
1853 ByteArray = array.array('B')\r
1854 ByteArray.fromfile(PeObject, 0x3E)\r
1855 ByteList = ByteArray.tolist()\r
1856 # DOS signature should be 'MZ'\r
1857 if self._ByteListToStr (ByteList[0x0:0x2]) != 'MZ':\r
1858 self.ErrorInfo = self.FileName + ' has no valid DOS signature MZ'\r
1859 return\r
1860\r
1861 # Read 4 byte PE Signature\r
1862 PeOffset = self._ByteListToInt(ByteList[0x3C:0x3E])\r
1863 PeObject.seek(PeOffset)\r
1864 ByteArray = array.array('B')\r
1865 ByteArray.fromfile(PeObject, 4)\r
1866 # PE signature should be 'PE\0\0'\r
1867 if ByteArray.tostring() != 'PE\0\0':\r
1868 self.ErrorInfo = self.FileName + ' has no valid PE signature PE00'\r
1869 return\r
1870\r
1871 # Read PE file header\r
1872 ByteArray = array.array('B')\r
1873 ByteArray.fromfile(PeObject, 0x14)\r
1874 ByteList = ByteArray.tolist()\r
1875 SecNumber = self._ByteListToInt(ByteList[0x2:0x4])\r
1876 if SecNumber == 0:\r
1877 self.ErrorInfo = self.FileName + ' has no section header'\r
1878 return\r
1879\r
1880 # Read PE optional header\r
1881 OptionalHeaderSize = self._ByteListToInt(ByteArray[0x10:0x12])\r
1882 ByteArray = array.array('B')\r
1883 ByteArray.fromfile(PeObject, OptionalHeaderSize)\r
1884 ByteList = ByteArray.tolist()\r
1885 self.EntryPoint = self._ByteListToInt(ByteList[0x10:0x14])\r
1886 self.SectionAlignment = self._ByteListToInt(ByteList[0x20:0x24])\r
1887 self.Size = self._ByteListToInt(ByteList[0x38:0x3C])\r
1888\r
1889 # Read each Section Header\r
1890 for Index in range(SecNumber):\r
1891 ByteArray = array.array('B')\r
1892 ByteArray.fromfile(PeObject, 0x28)\r
1893 ByteList = ByteArray.tolist()\r
1894 SecName = self._ByteListToStr(ByteList[0:8])\r
1895 SecVirtualSize = self._ByteListToInt(ByteList[8:12])\r
1896 SecRawAddress = self._ByteListToInt(ByteList[20:24])\r
1897 SecVirtualAddress = self._ByteListToInt(ByteList[12:16])\r
1898 self.SectionHeaderList.append((SecName, SecVirtualAddress, SecRawAddress, SecVirtualSize))\r
1899 self.IsValid = True\r
1900 PeObject.close()\r
1901\r
1902 def _ByteListToStr(self, ByteList):\r
1903 String = ''\r
1904 for index in range(len(ByteList)):\r
1905 if ByteList[index] == 0: \r
1906 break\r
1907 String += chr(ByteList[index])\r
1908 return String\r
1909\r
1910 def _ByteListToInt(self, ByteList):\r
1911 Value = 0\r
1912 for index in range(len(ByteList) - 1, -1, -1):\r
1913 Value = (Value << 8) | int(ByteList[index])\r
1914 return Value\r
1915\r
8518bf0b
LG
1916class DefaultStore():\r
1917 def __init__(self,DefaultStores ):\r
1918\r
1919 self.DefaultStores = DefaultStores\r
1920 def DefaultStoreID(self,DefaultStoreName):\r
1921 for key,value in self.DefaultStores.items():\r
1922 if value == DefaultStoreName:\r
1923 return key\r
1924 return None\r
1925 def GetDefaultDefault(self):\r
1926 if not self.DefaultStores or "0" in self.DefaultStores:\r
1927 return "0",TAB_DEFAULT_STORES_DEFAULT\r
1928 else:\r
8252e6bf 1929 minvalue = min(int(value_str) for value_str in self.DefaultStores)\r
8518bf0b
LG
1930 return (str(minvalue), self.DefaultStores[str(minvalue)])\r
1931 def GetMin(self,DefaultSIdList):\r
1932 if not DefaultSIdList:\r
4d3b9389 1933 return TAB_DEFAULT_STORES_DEFAULT\r
2b8a6c44
LG
1934 storeidset = {storeid for storeid, storename in self.DefaultStores.values() if storename in DefaultSIdList}\r
1935 if not storeidset:\r
1936 return ""\r
1937 minid = min(storeidset )\r
8518bf0b
LG
1938 for sid,name in self.DefaultStores.values():\r
1939 if sid == minid:\r
1940 return name\r
f51461c8
LG
1941class SkuClass():\r
1942 \r
1943 DEFAULT = 0\r
1944 SINGLE = 1\r
1945 MULTIPLE =2\r
1946 \r
8518bf0b
LG
1947 def __init__(self,SkuIdentifier='', SkuIds=None):\r
1948 if SkuIds is None:\r
1949 SkuIds = {}\r
c05c2c05
LG
1950\r
1951 for SkuName in SkuIds:\r
1952 SkuId = SkuIds[SkuName][0]\r
1953 skuid_num = int(SkuId,16) if SkuId.upper().startswith("0X") else int(SkuId)\r
e4ff28c3 1954 if skuid_num > 0xFFFFFFFFFFFFFFFF:\r
c05c2c05 1955 EdkLogger.error("build", PARAMETER_INVALID,\r
e4ff28c3
LG
1956 ExtraData = "SKU-ID [%s] value %s exceeds the max value of UINT64"\r
1957 % (SkuName, SkuId))\r
f51461c8
LG
1958 \r
1959 self.AvailableSkuIds = sdict()\r
1960 self.SkuIdSet = []\r
1ae469b9 1961 self.SkuIdNumberSet = []\r
8518bf0b
LG
1962 self.SkuData = SkuIds\r
1963 self.__SkuInherit = {}\r
c05c2c05 1964 self.__SkuIdentifier = SkuIdentifier\r
f51461c8
LG
1965 if SkuIdentifier == '' or SkuIdentifier is None:\r
1966 self.SkuIdSet = ['DEFAULT']\r
1ae469b9 1967 self.SkuIdNumberSet = ['0U']\r
f51461c8
LG
1968 elif SkuIdentifier == 'ALL':\r
1969 self.SkuIdSet = SkuIds.keys()\r
8518bf0b 1970 self.SkuIdNumberSet = [num[0].strip() + 'U' for num in SkuIds.values()]\r
f51461c8
LG
1971 else:\r
1972 r = SkuIdentifier.split('|') \r
8518bf0b 1973 self.SkuIdSet=[(r[k].strip()).upper() for k in range(len(r))]\r
1ae469b9
BF
1974 k = None\r
1975 try: \r
8518bf0b 1976 self.SkuIdNumberSet = [SkuIds[k][0].strip() + 'U' for k in self.SkuIdSet]\r
1ae469b9
BF
1977 except Exception:\r
1978 EdkLogger.error("build", PARAMETER_INVALID,\r
1979 ExtraData = "SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 1980 % (k, " | ".join(SkuIds.keys())))\r
f51461c8
LG
1981 for each in self.SkuIdSet:\r
1982 if each in SkuIds:\r
8518bf0b 1983 self.AvailableSkuIds[each] = SkuIds[each][0]\r
f51461c8
LG
1984 else:\r
1985 EdkLogger.error("build", PARAMETER_INVALID,\r
1986 ExtraData="SKU-ID [%s] is not supported by the platform. [Valid SKU-ID: %s]"\r
6035094d 1987 % (each, " | ".join(SkuIds.keys())))\r
8518bf0b
LG
1988 if self.SkuUsageType != self.SINGLE:\r
1989 self.AvailableSkuIds.update({'DEFAULT':0, 'COMMON':0})\r
e651d06c
LG
1990 if self.SkuIdSet:\r
1991 GlobalData.gSkuids = (self.SkuIdSet)\r
1992 if 'COMMON' in GlobalData.gSkuids:\r
1993 GlobalData.gSkuids.remove('COMMON')\r
8aaa8f7b
YZ
1994 if self.SkuUsageType == self.SINGLE:\r
1995 if len(GlobalData.gSkuids) != 1:\r
1996 if 'DEFAULT' in GlobalData.gSkuids:\r
1997 GlobalData.gSkuids.remove('DEFAULT')\r
e651d06c
LG
1998 if GlobalData.gSkuids:\r
1999 GlobalData.gSkuids.sort()\r
2000\r
8518bf0b
LG
2001 def GetNextSkuId(self, skuname):\r
2002 if not self.__SkuInherit:\r
2003 self.__SkuInherit = {}\r
2004 for item in self.SkuData.values():\r
2005 self.__SkuInherit[item[1]]=item[2] if item[2] else "DEFAULT"\r
2006 return self.__SkuInherit.get(skuname,"DEFAULT")\r
c05c2c05
LG
2007\r
2008 def GetSkuChain(self,sku):\r
09c80b07
B
2009 if sku == "DEFAULT":\r
2010 return ["DEFAULT"]\r
c05c2c05
LG
2011 skulist = [sku]\r
2012 nextsku = sku\r
2013 while 1:\r
2014 nextsku = self.GetNextSkuId(nextsku)\r
2015 skulist.append(nextsku)\r
2016 if nextsku == "DEFAULT":\r
2017 break\r
2018 skulist.reverse()\r
2019 return skulist\r
2020 def SkuOverrideOrder(self):\r
2021 skuorderset = []\r
2022 for skuname in self.SkuIdSet:\r
2023 skuorderset.append(self.GetSkuChain(skuname))\r
f51461c8 2024 \r
c05c2c05 2025 skuorder = []\r
8252e6bf 2026 for index in range(max(len(item) for item in skuorderset)):\r
c05c2c05
LG
2027 for subset in skuorderset:\r
2028 if index > len(subset)-1:\r
2029 continue\r
2030 if subset[index] in skuorder:\r
2031 continue\r
2032 skuorder.append(subset[index])\r
2033\r
2034 return skuorder\r
2035\r
f51461c8
LG
2036 def __SkuUsageType(self): \r
2037 \r
c05c2c05
LG
2038 if self.__SkuIdentifier.upper() == "ALL":\r
2039 return SkuClass.MULTIPLE\r
2040\r
f51461c8
LG
2041 if len(self.SkuIdSet) == 1:\r
2042 if self.SkuIdSet[0] == 'DEFAULT':\r
2043 return SkuClass.DEFAULT\r
2044 else:\r
2045 return SkuClass.SINGLE\r
c05c2c05
LG
2046 elif len(self.SkuIdSet) == 2:\r
2047 if 'DEFAULT' in self.SkuIdSet:\r
2048 return SkuClass.SINGLE\r
2049 else:\r
2050 return SkuClass.MULTIPLE\r
f51461c8
LG
2051 else:\r
2052 return SkuClass.MULTIPLE\r
8518bf0b 2053 def DumpSkuIdArrary(self):\r
f51461c8 2054\r
8518bf0b
LG
2055 ArrayStrList = []\r
2056 if self.SkuUsageType == SkuClass.SINGLE:\r
2057 ArrayStr = "{0x0}"\r
2058 else:\r
2059 for skuname in self.AvailableSkuIds:\r
2060 if skuname == "COMMON":\r
2061 continue\r
2062 while skuname != "DEFAULT":\r
2063 ArrayStrList.append(hex(int(self.AvailableSkuIds[skuname])))\r
2064 skuname = self.GetNextSkuId(skuname)\r
2065 ArrayStrList.append("0x0")\r
2066 ArrayStr = "{" + ",".join(ArrayStrList) + "}"\r
2067 return ArrayStr\r
f51461c8
LG
2068 def __GetAvailableSkuIds(self):\r
2069 return self.AvailableSkuIds\r
2070 \r
2071 def __GetSystemSkuID(self):\r
2072 if self.__SkuUsageType() == SkuClass.SINGLE:\r
c05c2c05
LG
2073 if len(self.SkuIdSet) == 1:\r
2074 return self.SkuIdSet[0]\r
2075 else:\r
2076 return self.SkuIdSet[0] if self.SkuIdSet[0] != 'DEFAULT' else self.SkuIdSet[1]\r
f51461c8
LG
2077 else:\r
2078 return 'DEFAULT'\r
1ae469b9
BF
2079 def __GetAvailableSkuIdNumber(self):\r
2080 return self.SkuIdNumberSet\r
f51461c8
LG
2081 SystemSkuId = property(__GetSystemSkuID)\r
2082 AvailableSkuIdSet = property(__GetAvailableSkuIds)\r
2083 SkuUsageType = property(__SkuUsageType)\r
1ae469b9 2084 AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber)\r
a3251d84
YL
2085\r
2086#\r
2087# Pack a registry format GUID\r
2088#\r
2089def PackRegistryFormatGuid(Guid):\r
d0a0c52c 2090 return PackGUID(Guid.split('-'))\r
a3251d84 2091\r
34952f49
LG
2092## Get the integer value from string like "14U" or integer like 2\r
2093#\r
2094# @param Input The object that may be either a integer value or a string\r
2095#\r
2096# @retval Value The integer value that the input represents\r
2097#\r
2098def GetIntegerValue(Input):\r
2099 if type(Input) in (int, long):\r
2100 return Input\r
2101 String = Input\r
2102 if String.endswith("U"):\r
2103 String = String[:-1]\r
2104 if String.endswith("ULL"):\r
2105 String = String[:-3]\r
2106 if String.endswith("LL"):\r
2107 String = String[:-2]\r
2108\r
2109 if String.startswith("0x") or String.startswith("0X"):\r
2110 return int(String, 16)\r
2111 elif String == '':\r
2112 return 0\r
2113 else:\r
2114 return int(String)\r
db55dac7 2115\r
d0a0c52c
CJ
2116#\r
2117# Pack a GUID (registry format) list into a buffer and return it\r
2118#\r
2119def PackGUID(Guid):\r
2120 return pack(PACK_PATTERN_GUID,\r
2121 int(Guid[0], 16),\r
2122 int(Guid[1], 16),\r
2123 int(Guid[2], 16),\r
2124 int(Guid[3][-4:-2], 16),\r
2125 int(Guid[3][-2:], 16),\r
2126 int(Guid[4][-12:-10], 16),\r
2127 int(Guid[4][-10:-8], 16),\r
2128 int(Guid[4][-8:-6], 16),\r
2129 int(Guid[4][-6:-4], 16),\r
2130 int(Guid[4][-4:-2], 16),\r
2131 int(Guid[4][-2:], 16)\r
2132 )\r
2133\r
2134#\r
2135# Pack a GUID (byte) list into a buffer and return it\r
2136#\r
2137def PackByteFormatGUID(Guid):\r
2138 return pack(PACK_PATTERN_GUID,\r
2139 Guid[0],\r
2140 Guid[1],\r
2141 Guid[2],\r
2142 Guid[3],\r
2143 Guid[4],\r
2144 Guid[5],\r
2145 Guid[6],\r
2146 Guid[7],\r
2147 Guid[8],\r
2148 Guid[9],\r
2149 Guid[10],\r
2150 )\r
2151\r
f51461c8
LG
2152##\r
2153#\r
2154# This acts like the main() function for the script, unless it is 'import'ed into another\r
2155# script.\r
2156#\r
2157if __name__ == '__main__':\r
2158 pass\r
2159\r