783f496d5f9b9daabc20f1c2e80c57c276528e0f
[people/mcb30/basetools.git] / Source / Python / Common / Misc.py
1 ## @file\r
2 # Common routines used by all tools\r
3 #\r
4 # Copyright (c) 2007, Intel Corporation\r
5 # All rights reserved. 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
17 import os\r
18 import sys\r
19 import string\r
20 import thread\r
21 import threading\r
22 import time\r
23 import re\r
24 import cPickle\r
25 from UserDict import IterableUserDict\r
26 from UserList import UserList\r
27 \r
28 from Common import EdkLogger as EdkLogger\r
29 from BuildToolError import *\r
30 \r
31 ## Regular expression used to find out place holders in string template\r
32 gPlaceholderPattern = re.compile("\$\{([^$()\s]+)\}", re.MULTILINE|re.UNICODE)\r
33 \r
34 ## Dictionary used to store file time stamp for quick re-access\r
35 gFileTimeStampCache = {}    # {file path : file time stamp}\r
36 \r
37 ## Dictionary used to store dependencies of files\r
38 gDependencyDatabase = {}    # arch : {file path : [dependent files list]}\r
39 \r
40 ## callback routine for processing variable option\r
41 #\r
42 # This function can be used to process variable number of option values. The\r
43 # typical usage of it is specify architecure list on command line.\r
44 # (e.g. <tool> -a IA32 X64 IPF)\r
45 #\r
46 # @param  Option        Standard callback function parameter\r
47 # @param  OptionString  Standard callback function parameter\r
48 # @param  Value         Standard callback function parameter\r
49 # @param  Parser        Standard callback function parameter\r
50 #\r
51 # @retval\r
52 #\r
53 def ProcessVariableArgument(Option, OptionString, Value, Parser):\r
54     assert Value is None\r
55     Value = []\r
56     RawArgs = Parser.rargs\r
57     while RawArgs:\r
58         Arg = RawArgs[0]\r
59         if (Arg[:2] == "--" and len(Arg) > 2) or \\r
60            (Arg[:1] == "-" and len(Arg) > 1 and Arg[1] != "-"):\r
61             break\r
62         Value.append(Arg)\r
63         del RawArgs[0]\r
64     setattr(Parser.values, Option.dest, Value)\r
65 \r
66 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style\r
67 #\r
68 #   @param      Guid    The GUID string\r
69 #\r
70 #   @retval     string  The GUID string in C structure style\r
71 #\r
72 def GuidStringToGuidStructureString(Guid):\r
73     GuidList = Guid.split('-')\r
74     Result = '{'\r
75     for Index in range(0,3,1):\r
76         Result = Result + '0x' + GuidList[Index] + ', '\r
77     Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]\r
78     for Index in range(0,12,2):\r
79         Result = Result + ', 0x' + GuidList[4][Index:Index+2]\r
80     Result += '}}'\r
81     return Result\r
82 \r
83 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
84 #\r
85 #   @param      GuidValue   The GUID value in C structure format\r
86 #\r
87 #   @retval     string      The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format\r
88 #\r
89 def GuidStructureStringToGuidString(GuidValue):\r
90     guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")\r
91     guidValueList = guidValueString.split(",")\r
92     if len(guidValueList) != 11:\r
93         EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
94     return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (\r
95             int(guidValueList[0], 16),\r
96             int(guidValueList[1], 16),\r
97             int(guidValueList[2], 16),\r
98             int(guidValueList[3], 16),\r
99             int(guidValueList[4], 16),\r
100             int(guidValueList[5], 16),\r
101             int(guidValueList[6], 16),\r
102             int(guidValueList[7], 16),\r
103             int(guidValueList[8], 16),\r
104             int(guidValueList[9], 16),\r
105             int(guidValueList[10], 16)\r
106             )\r
107 \r
108 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx\r
109 #\r
110 #   @param      GuidValue   The GUID value in C structure format\r
111 #\r
112 #   @retval     string      The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format\r
113 #\r
114 def GuidStructureStringToGuidValueName(GuidValue):\r
115     guidValueString = GuidValue.lower().replace("{", "").replace("}", "").replace(" ", "")\r
116     guidValueList = guidValueString.split(",")\r
117     if len(guidValueList) != 11:\r
118         EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)\r
119     return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (\r
120             int(guidValueList[0], 16),\r
121             int(guidValueList[1], 16),\r
122             int(guidValueList[2], 16),\r
123             int(guidValueList[3], 16),\r
124             int(guidValueList[4], 16),\r
125             int(guidValueList[5], 16),\r
126             int(guidValueList[6], 16),\r
127             int(guidValueList[7], 16),\r
128             int(guidValueList[8], 16),\r
129             int(guidValueList[9], 16),\r
130             int(guidValueList[10], 16)\r
131             )\r
132 \r
133 ## Create directories\r
134 #\r
135 #   @param      Directory   The directory name\r
136 #\r
137 def CreateDirectory(Directory):\r
138     if Directory == None or Directory.strip() == "":\r
139         return True\r
140     try:\r
141         if not os.access(Directory, os.F_OK):\r
142             os.makedirs(Directory)\r
143     except:\r
144         return False\r
145     return True\r
146 \r
147 ## Check if given file is changed or not\r
148 #\r
149 #  This method is used to check if a file is changed or not between two build\r
150 #  actions. It makes use a cache to store files timestamp.\r
151 #\r
152 #   @param      File    The path of file\r
153 #\r
154 #   @retval     True    If the given file is changed, doesn't exist, or can't be\r
155 #                       found in timestamp cache\r
156 #   @retval     False   If the given file is changed\r
157 #\r
158 def IsChanged(File):\r
159     if not os.path.exists(File):\r
160         return True\r
161 \r
162     FileState = os.stat(File)\r
163     TimeStamp = FileState[-2]\r
164 \r
165     if File in gFileTimeStampCache and TimeStamp <= gFileTimeStampCache[File]:\r
166         FileChanged = False\r
167     else:\r
168         FileChanged = True\r
169         gFileTimeStampCache[File] = TimeStamp\r
170 \r
171     return FileChanged\r
172 \r
173 ## Store content in file\r
174 #\r
175 #  This method is used to save file only when its content is changed. This is\r
176 #  quite useful for "make" system to decide what will be re-built and what won't.\r
177 #\r
178 #   @param      File            The path of file\r
179 #   @param      Content         The new content of the file\r
180 #   @param      IsBinaryFile    The flag indicating if the file is binary file or not\r
181 #\r
182 #   @retval     True            If the file content is changed and the file is renewed\r
183 #   @retval     False           If the file content is the same\r
184 #\r
185 def SaveFileOnChange(File, Content, IsBinaryFile=True):\r
186     if IsBinaryFile:\r
187         BinaryFlag = 'b'\r
188     else:\r
189         BinaryFlag = ''\r
190     Fd = None\r
191     if os.path.exists(File):\r
192         try:\r
193             Fd = open(File, "r"+BinaryFlag)\r
194         except:\r
195             EdkLogger.error(None, FILE_OPEN_FAILURE, ExtraData=File)\r
196         FileSize = os.fstat(Fd.fileno()).st_size\r
197         if len(Content) == FileSize and Content == Fd.read():\r
198             Fd.close()\r
199             return False\r
200         Fd.close()\r
201         # os.remove(File) # seems creating new file is faster than overwriting old one\r
202     CreateDirectory(os.path.dirname(File))\r
203     try:\r
204         Fd = open(File, "w"+BinaryFlag)\r
205     except:\r
206         EdkLogger.error(None, FILE_CREATE_FAILURE, ExtraData=File)\r
207     Fd.write(Content)\r
208     Fd.close()\r
209     return True\r
210 \r
211 ## Make a Python object persistent on file system\r
212 #\r
213 #   @param      Data    The object to be stored in file\r
214 #   @param      File    The path of file to store the object\r
215 #\r
216 def DataDump(Data, File):\r
217     Fd = None\r
218     try:\r
219         Fd = open(File, 'wb')\r
220         cPickle.dump(Data, Fd, cPickle.HIGHEST_PROTOCOL)\r
221     except:\r
222         EdkLogger.error("", FILE_OPEN_FAILURE, ExtraData=File, RaiseError=False)\r
223     finally:\r
224         if Fd != None:\r
225             Fd.close()\r
226 \r
227 ## Restore a Python object from a file\r
228 #\r
229 #   @param      File    The path of file stored the object\r
230 #\r
231 #   @retval     object  A python object\r
232 #   @retval     None    If failure in file operation\r
233 #\r
234 def DataRestore(File):\r
235     Data = None\r
236     Fd = None\r
237     try:\r
238         Fd = open(File, 'rb')\r
239         Data = cPickle.load(Fd)\r
240     except Exception, e:\r
241         EdkLogger.verbose("Failed to load [%s]\n\t%s" % (File, str(e)))\r
242         Data = None\r
243     finally:\r
244         if Fd != None:\r
245             Fd.close()\r
246     return Data\r
247 \r
248 ## Check if gvien file exists or not\r
249\r
250 #   @param      File    File name or path to be checked\r
251 #   @param      Dir     The directory the file is relative to\r
252\r
253 #   @retval     True    if file exists\r
254 #   @retval     False   if file doesn't exists\r
255\r
256 def ValidFile(File, Dir='.'):\r
257     Wd = os.getcwd()\r
258     os.chdir(Dir)\r
259     if not os.path.exists(File):\r
260         os.chdir(Wd)\r
261         return False\r
262     os.chdir(Wd)\r
263     return True\r
264 \r
265 ## Get GUID value from given packages\r
266\r
267 #   @param      CName           The CName of the GUID\r
268 #   @param      PackageList     List of packages looking-up in\r
269\r
270 #   @retval     GuidValue   if the CName is found in any given package\r
271 #   @retval     None        if the CName is not found in all given packages\r
272\r
273 def GuidValue(CName, PackageList):\r
274     for P in PackageList:\r
275         if CName in P.Guids:\r
276             return P.Guids[CName]\r
277         if CName in P.Protocols:\r
278             return P.Protocols[CName]\r
279         if CName in P.Ppis:\r
280             return P.Ppis[CName]\r
281     return None\r
282 \r
283 ## A string template class\r
284 #\r
285 #  This class implements a template for string replacement. A string template\r
286 #  looks like following\r
287 #\r
288 #       ${BEGIN} other_string ${placeholder_name} other_string ${END}\r
289 #\r
290 #  The string between ${BEGIN} and ${END} will be repeated as many times as the\r
291 #  length of "placeholder_name", which is a list passed through a dict. The\r
292 #  "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can\r
293 #  be not used and, in this case, the "placeholder_name" must not a list and it\r
294 #  will just be replaced once.\r
295 #\r
296 class TemplateString(object):\r
297     ## Constructor\r
298     def __init__(self):\r
299         self.String = ''\r
300 \r
301     ## str() operator\r
302     #\r
303     #   @retval     string  The string replaced\r
304     #\r
305     def __str__(self):\r
306         return self.String\r
307 \r
308     ## Replace the string template with dictionary of placeholders\r
309     #\r
310     #   @param      AppendString    The string template to append\r
311     #   @param      Dictionary      The placeholder dictionaries\r
312     #\r
313     def Append(self, AppendString, Dictionary=None):\r
314         if Dictionary == None:\r
315             self.String += AppendString\r
316             return\r
317 \r
318         # replace repeat ones, enclosed by ${BEGIN} and $(END)\r
319         while True:\r
320             Start = AppendString.find('${BEGIN}')\r
321             if Start < 0:\r
322                 break\r
323             End   = AppendString.find('${END}')\r
324 \r
325             # exclude the ${BEGIN} and ${END}\r
326             SubString = AppendString[Start + 8 : End]\r
327 \r
328             RepeatTime = -1\r
329             SubDict = {}\r
330             PlaceholderList = gPlaceholderPattern.findall(SubString)\r
331             for Key in PlaceholderList:\r
332                 if Key not in Dictionary:\r
333                     continue\r
334 \r
335                 Value = Dictionary[Key]\r
336                 if type(Value) != type([]):\r
337                     continue\r
338 \r
339                 SubDict[Key] = ""\r
340                 if RepeatTime < 0:\r
341                     RepeatTime = len(Value)\r
342                 elif RepeatTime != len(Value):\r
343                     EdkLogger.error("TemplateString", PARAMETER_INVALID, Key + " has different repeat time from others!",\r
344                                     ExtraData=str(Dictionary))\r
345 \r
346             NewString = ''\r
347             for Index in range(0, RepeatTime):\r
348                 for Key in SubDict:\r
349                     SubDict[Key] = Dictionary[Key][Index]\r
350                 NewString += string.Template(SubString).safe_substitute(SubDict)\r
351             AppendString = AppendString[0:Start] + NewString + AppendString[End + 6:]\r
352 \r
353         # replace single ones\r
354         SubDict = {}\r
355         for Key in Dictionary:\r
356             Value = Dictionary[Key]\r
357             if type(Value) == type([]):\r
358                 continue\r
359             SubDict[Key] = Value\r
360         AppendString = string.Template(AppendString).safe_substitute(SubDict)\r
361 \r
362         self.String += AppendString\r
363 \r
364 ## Progress indicator class\r
365 #\r
366 #  This class makes use of thread to print progress on console.\r
367 #\r
368 class Progressor:\r
369     # for avoiding deadloop\r
370     _StopFlag = None\r
371     _ProgressThread = None\r
372     ## Constructor\r
373     #\r
374     #   @param      OpenMessage     The string printed before progress charaters\r
375     #   @param      CloseMessage    The string printed after progress charaters\r
376     #   @param      ProgressChar    The charater used to indicate the progress\r
377     #   @param      Interval        The interval in seconds between two progress charaters\r
378     #\r
379     def __init__(self, OpenMessage="", CloseMessage="", ProgressChar='.', Interval=1):\r
380         self.PromptMessage = OpenMessage\r
381         self.CodaMessage = CloseMessage\r
382         self.ProgressChar = ProgressChar\r
383         self.Interval = Interval\r
384         if Progressor._StopFlag == None:\r
385             Progressor._StopFlag = threading.Event()\r
386 \r
387     ## Start to print progress charater\r
388     #\r
389     #   @param      OpenMessage     The string printed before progress charaters\r
390     #\r
391     def Start(self, OpenMessage=None):\r
392         if OpenMessage != None:\r
393             self.PromptMessage = OpenMessage\r
394         Progressor._StopFlag.clear()\r
395         if Progressor._ProgressThread == None:\r
396             Progressor._ProgressThread = threading.Thread(target=self._ProgressThreadEntry)\r
397             Progressor._ProgressThread.setDaemon(False)\r
398             Progressor._ProgressThread.start()\r
399 \r
400     ## Stop printing progress charater\r
401     #\r
402     #   @param      CloseMessage    The string printed after progress charaters\r
403     #\r
404     def Stop(self, CloseMessage=None):\r
405         OriginalCodaMessage = self.CodaMessage\r
406         if CloseMessage != None:\r
407             self.CodaMessage = CloseMessage\r
408         self.Abort()\r
409         self.CodaMessage = OriginalCodaMessage\r
410 \r
411     ## Thread entry method\r
412     def _ProgressThreadEntry(self):\r
413         print self.PromptMessage,\r
414         sys.stdout.flush()\r
415         while not Progressor._StopFlag.isSet():\r
416             print self.ProgressChar,\r
417             sys.stdout.flush()\r
418             time.sleep(self.Interval)\r
419         print self.CodaMessage\r
420         sys.stdout.flush()\r
421 \r
422     ## Abort the progress display\r
423     @staticmethod\r
424     def Abort():\r
425         if Progressor._StopFlag != None:\r
426             Progressor._StopFlag.set()\r
427         if Progressor._ProgressThread != None:\r
428             Progressor._ProgressThread.join()\r
429             Progressor._ProgressThread = None\r
430 \r
431 ## A dict which can access its keys and/or values orderly\r
432 #\r
433 #  The class implements a new kind of dict which its keys or values can be\r
434 #  accessed in the order they are added into the dict. It guarantees the order\r
435 #  by making use of an internal list to keep a copy of keys.\r
436 #\r
437 class sdict(IterableUserDict):\r
438     ## Constructor\r
439     def __init__(self):\r
440         IterableUserDict.__init__(self)\r
441         self._key_list = []\r
442 \r
443     ## [] operator\r
444     def __setitem__(self, key, value):\r
445         if key not in self._key_list:\r
446             self._key_list.append(key)\r
447         IterableUserDict.__setitem__(self, key, value)\r
448 \r
449     ## del operator\r
450     def __delitem__(self, key):\r
451         self._key_list.remove(key)\r
452         IterableUserDict.__delitem__(self, key)\r
453 \r
454     ## used in "for k in dict" loop to ensure the correct order\r
455     def __iter__(self):\r
456         return self.iterkeys()\r
457 \r
458     ## len() support\r
459     def __len__(self):\r
460         return len(self._key_list)\r
461 \r
462     ## "in" test support\r
463     def __contains__(self, key):\r
464         return key in self._key_list\r
465     \r
466     ## indexof support\r
467     def index(self, key):\r
468         return self._key_list.index(key)\r
469     \r
470     ## insert support\r
471     def insert(self, key, newkey, newvalue, order):\r
472         index = self._key_list.index(key)\r
473         if order == 'BEFORE':\r
474             self._key_list.insert(index, newkey)\r
475             IterableUserDict.__setitem__(self, newkey, newvalue)\r
476         elif order == 'AFTER':\r
477             self._key_list.insert(index + 1, newkey)\r
478             IterableUserDict.__setitem__(self, newkey, newvalue)\r
479 \r
480 \r
481     def has_key(self, key):\r
482         return key in self._key_list\r
483 \r
484     ## Empty the dict\r
485     def clear(self):\r
486         self._key_list = []\r
487         IterableUserDict.clear(self)\r
488 \r
489     ## Return a copy of keys\r
490     def keys(self):\r
491         keys = []\r
492         for key in self._key_list:\r
493             keys.append(key)\r
494         return keys\r
495 \r
496     ## Return a copy of values\r
497     def values(self):\r
498         values = []\r
499         for key in self._key_list:\r
500             values.append(self[key])\r
501         return values\r
502 \r
503     ## Return a copy of (key, value) list\r
504     def items(self):\r
505         items = []\r
506         for key in self._key_list:\r
507             items.append((key, self[key]))\r
508         return items\r
509 \r
510     ## Iteration support\r
511     def iteritems(self):\r
512         return iter(self.items())\r
513 \r
514     ## Keys interation support\r
515     def iterkeys(self):\r
516         return iter(self.keys())\r
517 \r
518     ## Values interation support\r
519     def itervalues(self):\r
520         return iter(self.values())\r
521 \r
522     ## Return value related to a key, and remove the (key, value) from the dict\r
523     def pop(self, key, *dv):\r
524         value = None\r
525         if key in self._key_list:\r
526             value = self[key]\r
527             self.__delitem__(key)\r
528         elif len(dv) != 0 :\r
529             value = kv[0]\r
530         return value\r
531 \r
532     ## Return (key, value) pair, and remove the (key, value) from the dict\r
533     def popitem(self):\r
534         key = self._key_list[-1]\r
535         value = self[key]\r
536         self.__delitem__(key)\r
537         return key, value\r
538 \r
539     def update(self, dict=None, **kwargs):\r
540         if dict != None:\r
541             for k, v in dict.items():\r
542                 self[k] = v\r
543         if len(kwargs):\r
544             for k, v in kwargs.items():\r
545                 self[k] = v\r
546 \r
547 ## Dictionary with restricted keys\r
548 #\r
549 class rdict(dict):\r
550     ## Constructor\r
551     def __init__(self, KeyList):\r
552         for Key in KeyList:\r
553             dict.__setitem__(self, Key, "")\r
554 \r
555     ## []= operator\r
556     def __setitem__(self, key, value):\r
557         if key not in self:\r
558             EdkLogger.error("RestrictedDict", ATTRIBUTE_SET_FAILURE, "Key [%s] is not allowed" % key, \r
559                             ExtraData=", ".join(dict.keys(self)))\r
560         dict.__setitem__(self, key, value)\r
561 \r
562     ## =[] operator\r
563     def __getitem__(self, key):\r
564         if key not in self:\r
565             return ""\r
566         return dict.__getitem__(self, key)\r
567 \r
568     ## del operator\r
569     def __delitem__(self, key):\r
570         EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="del")\r
571 \r
572     ## Empty the dict\r
573     def clear(self):\r
574         for Key in self:\r
575             self.__setitem__(Key, "")\r
576 \r
577     ## Return value related to a key, and remove the (key, value) from the dict\r
578     def pop(self, key, *dv):\r
579         EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="pop")\r
580 \r
581     ## Return (key, value) pair, and remove the (key, value) from the dict\r
582     def popitem(self):\r
583         EdkLogger.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED, ExtraData="popitem")\r
584 \r
585 ## Dictionary using prioritized list as key\r
586 #\r
587 class tdict:\r
588     _ListType = type([])\r
589     _TupleType = type(())\r
590     _Wildcard = 'COMMON'\r
591     _ValidWildcardList = ['COMMON', 'DEFAULT', 'ALL', '', '*', 'PLATFORM']\r
592 \r
593     def __init__(self, _Single_=False, _Level_=2):\r
594         self._Level_ = _Level_\r
595         self.data = {}\r
596         self._Single_ = _Single_\r
597     \r
598     # =[] operator\r
599     def __getitem__(self, key):\r
600         KeyType = type(key)\r
601         RestKeys = None\r
602         if KeyType == self._ListType or KeyType == self._TupleType:\r
603             FirstKey = key[0]\r
604             if len(key) > 1:\r
605                 RestKeys = key[1:]\r
606             elif self._Level_ > 1:\r
607                 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]\r
608         else:\r
609             FirstKey = key\r
610             if self._Level_ > 1:\r
611                 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]\r
612 \r
613         if FirstKey == None or str(FirstKey).upper() in self._ValidWildcardList:\r
614             FirstKey = self._Wildcard\r
615 \r
616         if self._Single_:\r
617             return self._GetSingleValue(FirstKey, RestKeys)\r
618         else:\r
619             return self._GetAllValues(FirstKey, RestKeys)\r
620 \r
621     def _GetSingleValue(self, FirstKey, RestKeys):\r
622         Value = None\r
623         #print "%s-%s" % (FirstKey, self._Level_) ,\r
624         if self._Level_ > 1:\r
625             if FirstKey == self._Wildcard:\r
626                 if FirstKey in self.data:\r
627                     Value = self.data[FirstKey][RestKeys]\r
628                 if Value == None:\r
629                     for Key in self.data:\r
630                         Value = self.data[Key][RestKeys]\r
631                         if Value != None: break\r
632             else:\r
633                 if FirstKey in self.data:\r
634                     Value = self.data[FirstKey][RestKeys]\r
635                 if Value == None and self._Wildcard in self.data:\r
636                     #print "Value=None"\r
637                     Value = self.data[self._Wildcard][RestKeys]\r
638         else:\r
639             if FirstKey == self._Wildcard:\r
640                 if FirstKey in self.data:\r
641                     Value = self.data[FirstKey]\r
642                 if Value == None:\r
643                     for Key in self.data:\r
644                         Value = self.data[Key]\r
645                         if Value != None: break\r
646             else:\r
647                 if FirstKey in self.data:\r
648                     Value = self.data[FirstKey]\r
649                 elif self._Wildcard in self.data:\r
650                     Value = self.data[self._Wildcard]\r
651         return Value\r
652 \r
653     def _GetAllValues(self, FirstKey, RestKeys):\r
654         Value = []\r
655         if self._Level_ > 1:\r
656             if FirstKey == self._Wildcard:\r
657                 for Key in self.data:\r
658                     Value += self.data[Key][RestKeys]\r
659             else:\r
660                 if FirstKey in self.data:\r
661                     Value += self.data[FirstKey][RestKeys]\r
662                 if self._Wildcard in self.data:\r
663                     Value += self.data[self._Wildcard][RestKeys]\r
664         else:\r
665             if FirstKey == self._Wildcard:\r
666                 for Key in self.data:\r
667                     Value.append(self.data[Key])\r
668             else:\r
669                 if FirstKey in self.data:\r
670                     Value.append(self.data[FirstKey])\r
671                 if self._Wildcard in self.data:\r
672                     Value.append(self.data[self._Wildcard])\r
673         return Value\r
674 \r
675     ## []= operator\r
676     def __setitem__(self, key, value):\r
677         KeyType = type(key)\r
678         RestKeys = None\r
679         if KeyType == self._ListType or KeyType == self._TupleType:\r
680             FirstKey = key[0]\r
681             if len(key) > 1:\r
682                 RestKeys = key[1:]\r
683             else:\r
684                 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]\r
685         else:\r
686             FirstKey = key\r
687             if self._Level_ > 1:\r
688                 RestKeys = [self._Wildcard for i in range(0, self._Level_-1)]\r
689 \r
690         if FirstKey in self._ValidWildcardList:\r
691             FirstKey = self._Wildcard\r
692         \r
693         if FirstKey not in self.data and self._Level_ > 0:\r
694             self.data[FirstKey] = tdict(self._Single_, self._Level_ - 1)\r
695 \r
696         if self._Level_ > 1:\r
697             self.data[FirstKey][RestKeys] = value\r
698         else:\r
699             self.data[FirstKey] = value\r
700 \r
701     def SetGreedyMode(self):\r
702         self._Single_ = False\r
703         if self._Level_ > 1:\r
704             for Key in self.data:\r
705                 self.data[Key].SetGreedyMode()\r
706 \r
707     def SetSingleMode(self):\r
708         self._Single_ = True\r
709         if self._Level_ > 1:\r
710             for Key in self.data:\r
711                 self.data[Key].SetSingleMode()\r
712 \r
713 ## Boolean chain list\r
714\r
715 class Blist(UserList):\r
716     def __init__(self, initlist=None):\r
717         UserList.__init__(self, initlist)\r
718     def __setitem__(self, i, item):\r
719         if item not in [True, False]:\r
720             if item == 0:\r
721                 item = False\r
722             else:\r
723                 item = True\r
724         self.data[i] = item\r
725     def _GetResult(self):\r
726         Value = True\r
727         for item in self.data:\r
728             Value &= item\r
729         return Value\r
730     Result = property(_GetResult)\r
731 \r
732 ##\r
733 #\r
734 # This acts like the main() function for the script, unless it is 'import'ed into another\r
735 # script.\r
736 #\r
737 if __name__ == '__main__':\r
738     d = tdict(True, 3)\r
739     d['COMMON', 'PEIM', "A",] = 1\r
740     d['COMMON', 'DXE_CORE', 'B'] = 2\r
741     d['IA32', 'DXE_CORE', 'C'] = 3\r
742 \r
743     print d['IA32', 'DXE_CORE', 'C']\r
744     \r
745     s = sdict()\r
746     s[1] = 1\r
747     s[3] = 3\r
748     s[4] = 4\r
749     s[6] = 6\r
750     print s.index(3)\r
751     s.insert(3, 2, 2, 'BEFORE')\r
752     print s.index(3)\r
753     print s.index(4)\r
754     s.insert(3, 5, 5, 'AFTER')\r
755     print s.keys()\r
756     print s.values()\r
757     for item in s:\r
758         print item, s[item]\r
759 \r