]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Common/Misc.py
2 # Common routines used by all tools
4 # Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 from UserDict
import IterableUserDict
27 from UserList
import UserList
29 from Common
import EdkLogger
as EdkLogger
30 from Common
import GlobalData
as GlobalData
31 from DataType
import *
32 from BuildToolError
import *
34 ## Regular expression used to find out place holders in string template
35 gPlaceholderPattern
= re
.compile("\$\{([^$()\s]+)\}", re
.MULTILINE|re
.UNICODE
)
37 ## Dictionary used to store file time stamp for quick re-access
38 gFileTimeStampCache
= {} # {file path : file time stamp}
40 ## Dictionary used to store dependencies of files
41 gDependencyDatabase
= {} # arch : {file path : [dependent files list]}
43 ## callback routine for processing variable option
45 # This function can be used to process variable number of option values. The
46 # typical usage of it is specify architecure list on command line.
47 # (e.g. <tool> -a IA32 X64 IPF)
49 # @param Option Standard callback function parameter
50 # @param OptionString Standard callback function parameter
51 # @param Value Standard callback function parameter
52 # @param Parser Standard callback function parameter
56 def ProcessVariableArgument(Option
, OptionString
, Value
, Parser
):
59 RawArgs
= Parser
.rargs
62 if (Arg
[:2] == "--" and len(Arg
) > 2) or \
63 (Arg
[:1] == "-" and len(Arg
) > 1 and Arg
[1] != "-"):
67 setattr(Parser
.values
, Option
.dest
, Value
)
69 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C structure style
71 # @param Guid The GUID string
73 # @retval string The GUID string in C structure style
75 def GuidStringToGuidStructureString(Guid
):
76 GuidList
= Guid
.split('-')
78 for Index
in range(0,3,1):
79 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
80 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
81 for Index
in range(0,12,2):
82 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+2]
86 ## Convert GUID structure in byte array to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
88 # @param GuidValue The GUID value in byte array
90 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
92 def GuidStructureByteArrayToGuidString(GuidValue
):
93 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
94 guidValueList
= guidValueString
.split(",")
95 if len(guidValueList
) != 16:
97 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
99 return "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
100 int(guidValueList
[3], 16),
101 int(guidValueList
[2], 16),
102 int(guidValueList
[1], 16),
103 int(guidValueList
[0], 16),
104 int(guidValueList
[5], 16),
105 int(guidValueList
[4], 16),
106 int(guidValueList
[7], 16),
107 int(guidValueList
[6], 16),
108 int(guidValueList
[8], 16),
109 int(guidValueList
[9], 16),
110 int(guidValueList
[10], 16),
111 int(guidValueList
[11], 16),
112 int(guidValueList
[12], 16),
113 int(guidValueList
[13], 16),
114 int(guidValueList
[14], 16),
115 int(guidValueList
[15], 16)
120 ## Convert GUID string in C structure style to xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
122 # @param GuidValue The GUID value in C structure format
124 # @retval string The GUID value in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format
126 def GuidStructureStringToGuidString(GuidValue
):
127 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "").replace(";", "")
128 guidValueList
= guidValueString
.split(",")
129 if len(guidValueList
) != 11:
131 #EdkLogger.error(None, None, "Invalid GUID value string %s" % GuidValue)
133 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
134 int(guidValueList
[0], 16),
135 int(guidValueList
[1], 16),
136 int(guidValueList
[2], 16),
137 int(guidValueList
[3], 16),
138 int(guidValueList
[4], 16),
139 int(guidValueList
[5], 16),
140 int(guidValueList
[6], 16),
141 int(guidValueList
[7], 16),
142 int(guidValueList
[8], 16),
143 int(guidValueList
[9], 16),
144 int(guidValueList
[10], 16)
149 ## Convert GUID string in C structure style to xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx
151 # @param GuidValue The GUID value in C structure format
153 # @retval string The GUID value in xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx format
155 def GuidStructureStringToGuidValueName(GuidValue
):
156 guidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").replace(" ", "")
157 guidValueList
= guidValueString
.split(",")
158 if len(guidValueList
) != 11:
159 EdkLogger
.error(None, None, "Invalid GUID value string %s" % GuidValue
)
160 return "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x" % (
161 int(guidValueList
[0], 16),
162 int(guidValueList
[1], 16),
163 int(guidValueList
[2], 16),
164 int(guidValueList
[3], 16),
165 int(guidValueList
[4], 16),
166 int(guidValueList
[5], 16),
167 int(guidValueList
[6], 16),
168 int(guidValueList
[7], 16),
169 int(guidValueList
[8], 16),
170 int(guidValueList
[9], 16),
171 int(guidValueList
[10], 16)
174 ## Create directories
176 # @param Directory The directory name
178 def CreateDirectory(Directory
):
179 if Directory
== None or Directory
.strip() == "":
182 if not os
.access(Directory
, os
.F_OK
):
183 os
.makedirs(Directory
)
188 ## Remove directories, including files and sub-directories in it
190 # @param Directory The directory name
192 def RemoveDirectory(Directory
, Recursively
=False):
193 if Directory
== None or Directory
.strip() == "" or not os
.path
.exists(Directory
):
196 CurrentDirectory
= os
.getcwd()
198 for File
in os
.listdir("."):
199 if os
.path
.isdir(File
):
200 RemoveDirectory(File
, Recursively
)
203 os
.chdir(CurrentDirectory
)
206 ## Check if given file is changed or not
208 # This method is used to check if a file is changed or not between two build
209 # actions. It makes use a cache to store files timestamp.
211 # @param File The path of file
213 # @retval True If the given file is changed, doesn't exist, or can't be
214 # found in timestamp cache
215 # @retval False If the given file is changed
218 if not os
.path
.exists(File
):
221 FileState
= os
.stat(File
)
222 TimeStamp
= FileState
[-2]
224 if File
in gFileTimeStampCache
and TimeStamp
== gFileTimeStampCache
[File
]:
228 gFileTimeStampCache
[File
] = TimeStamp
232 ## Store content in file
234 # This method is used to save file only when its content is changed. This is
235 # quite useful for "make" system to decide what will be re-built and what won't.
237 # @param File The path of file
238 # @param Content The new content of the file
239 # @param IsBinaryFile The flag indicating if the file is binary file or not
241 # @retval True If the file content is changed and the file is renewed
242 # @retval False If the file content is the same
244 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
246 Content
= Content
.replace("\n", os
.linesep
)
248 if os
.path
.exists(File
):
250 if Content
== open(File
, "rb").read():
253 EdkLogger
.error(None, FILE_OPEN_FAILURE
, ExtraData
=File
)
255 CreateDirectory(os
.path
.dirname(File
))
257 if GlobalData
.gIsWindows
:
259 from PyUtility
import SaveFileToDisk
260 if not SaveFileToDisk(File
, Content
):
261 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
263 Fd
= open(File
, "wb")
267 Fd
= open(File
, "wb")
271 EdkLogger
.error(None, FILE_CREATE_FAILURE
, ExtraData
=File
)
275 ## Make a Python object persistent on file system
277 # @param Data The object to be stored in file
278 # @param File The path of file to store the object
280 def DataDump(Data
, File
):
283 Fd
= open(File
, 'wb')
284 cPickle
.dump(Data
, Fd
, cPickle
.HIGHEST_PROTOCOL
)
286 EdkLogger
.error("", FILE_OPEN_FAILURE
, ExtraData
=File
, RaiseError
=False)
291 ## Restore a Python object from a file
293 # @param File The path of file stored the object
295 # @retval object A python object
296 # @retval None If failure in file operation
298 def DataRestore(File
):
302 Fd
= open(File
, 'rb')
303 Data
= cPickle
.load(Fd
)
305 EdkLogger
.verbose("Failed to load [%s]\n\t%s" % (File
, str(e
)))
312 ## Retrieve and cache the real path name in file system
314 # @param Root The root directory of path relative to
316 # @retval str The path string if the path exists
317 # @retval None If path doesn't exist
323 def __init__(self
, Root
):
325 for F
in os
.listdir(Root
):
327 self
._UPPER
_CACHE
_[F
.upper()] = F
330 def __getitem__(self
, Path
):
331 Path
= Path
[len(os
.path
.commonprefix([Path
, self
._Root
])):]
334 if Path
and Path
[0] == os
.path
.sep
:
336 if Path
in self
._CACHE
_:
337 return os
.path
.join(self
._Root
, Path
)
338 UpperPath
= Path
.upper()
339 if UpperPath
in self
._UPPER
_CACHE
_:
340 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
344 SepIndex
= Path
.find(os
.path
.sep
)
346 Parent
= UpperPath
[:SepIndex
]
347 if Parent
not in self
._UPPER
_CACHE
_:
349 LastSepIndex
= SepIndex
350 SepIndex
= Path
.find(os
.path
.sep
, LastSepIndex
+ 1)
352 if LastSepIndex
== -1:
357 SepIndex
= LastSepIndex
359 Parent
= Path
[:SepIndex
]
360 ParentKey
= UpperPath
[:SepIndex
]
361 if ParentKey
not in self
._UPPER
_CACHE
_:
365 if Parent
in self
._CACHE
_:
368 ParentDir
= self
._UPPER
_CACHE
_[ParentKey
]
369 for F
in os
.listdir(ParentDir
):
370 Dir
= os
.path
.join(ParentDir
, F
)
371 self
._CACHE
_.add(Dir
)
372 self
._UPPER
_CACHE
_[Dir
.upper()] = Dir
374 SepIndex
= Path
.find(os
.path
.sep
, SepIndex
+ 1)
377 if Path
in self
._CACHE
_:
378 return os
.path
.join(self
._Root
, Path
)
379 elif UpperPath
in self
._UPPER
_CACHE
_:
380 return os
.path
.join(self
._Root
, self
._UPPER
_CACHE
_[UpperPath
])
383 ## Get all files of a directory
385 # @param Root: Root dir
386 # @param SkipList : The files need be skipped
388 # @retval A list of all files
390 def GetFiles(Root
, SkipList
=None, FullPath
= True):
393 for Root
, Dirs
, Files
in os
.walk(Root
):
395 for Item
in SkipList
:
400 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
402 File
= File
[len(OriPath
) + 1:]
403 FileList
.append(File
)
407 ## Check if gvien file exists or not
409 # @param File File name or path to be checked
410 # @param Dir The directory the file is relative to
412 # @retval True if file exists
413 # @retval False if file doesn't exists
415 def ValidFile(File
, Ext
=None):
417 Dummy
, FileExt
= os
.path
.splitext(File
)
418 if FileExt
.lower() != Ext
.lower():
420 if not os
.path
.exists(File
):
424 def RealPath(File
, Dir
='', OverrideDir
=''):
425 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
426 NewFile
= GlobalData
.gAllFiles
[NewFile
]
427 if not NewFile
and OverrideDir
:
428 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
429 NewFile
= GlobalData
.gAllFiles
[NewFile
]
432 def RealPath2(File
, Dir
='', OverrideDir
=''):
434 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
436 if OverrideDir
[-1] == os
.path
.sep
:
437 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
439 return NewFile
[len(OverrideDir
)+1:], NewFile
[0:len(OverrideDir
)]
441 NewFile
= GlobalData
.gAllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
444 if Dir
[-1] == os
.path
.sep
:
445 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
447 return NewFile
[len(Dir
)+1:], NewFile
[0:len(Dir
)]
453 ## Check if gvien file exists or not
456 def ValidFile2(AllFiles
, File
, Ext
=None, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
459 Dummy
, FileExt
= os
.path
.splitext(File
)
460 if FileExt
.lower() != Ext
.lower():
463 # Replace the R8 macros
464 if OverrideDir
!= '' and OverrideDir
!= None:
465 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
466 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
467 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
468 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
470 # Replace the default dir to current dir
473 Dir
= Dir
[len(Workspace
)+1:]
475 # First check if File has R8 definition itself
476 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
477 NewFile
= File
.replace('$(EFI_SOURCE)', EfiSource
)
478 NewFile
= NewFile
.replace('$(EDK_SOURCE)', EdkSource
)
479 NewFile
= AllFiles
[os
.path
.normpath(NewFile
)]
483 # Second check the path with override value
484 if OverrideDir
!= '' and OverrideDir
!= None:
485 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
489 # Last check the path with normal definitions
490 File
= os
.path
.join(Dir
, File
)
491 NewFile
= AllFiles
[os
.path
.normpath(File
)]
497 ## Check if gvien file exists or not
500 def ValidFile3(AllFiles
, File
, Workspace
='', EfiSource
='', EdkSource
='', Dir
='.', OverrideDir
=''):
501 # Replace the R8 macros
502 if OverrideDir
!= '' and OverrideDir
!= None:
503 if OverrideDir
.find('$(EFI_SOURCE)') > -1:
504 OverrideDir
= OverrideDir
.replace('$(EFI_SOURCE)', EfiSource
)
505 if OverrideDir
.find('$(EDK_SOURCE)') > -1:
506 OverrideDir
= OverrideDir
.replace('$(EDK_SOURCE)', EdkSource
)
508 # Replace the default dir to current dir
509 # Dir is current module dir related to workspace
512 Dir
= Dir
[len(Workspace
)+1:]
515 RelaPath
= AllFiles
[os
.path
.normpath(Dir
)]
516 NewRelaPath
= RelaPath
519 # First check if File has R8 definition itself
520 if File
.find('$(EFI_SOURCE)') > -1 or File
.find('$(EDK_SOURCE)') > -1:
521 File
= File
.replace('$(EFI_SOURCE)', EfiSource
)
522 File
= File
.replace('$(EDK_SOURCE)', EdkSource
)
523 NewFile
= AllFiles
[os
.path
.normpath(File
)]
525 NewRelaPath
= os
.path
.dirname(NewFile
)
526 File
= os
.path
.basename(NewFile
)
527 #NewRelaPath = NewFile[:len(NewFile) - len(File.replace("..\\", '').replace("../", '')) - 1]
530 # Second check the path with override value
531 if OverrideDir
!= '' and OverrideDir
!= None:
532 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(OverrideDir
, File
))]
534 #NewRelaPath = os.path.dirname(NewFile)
535 NewRelaPath
= NewFile
[:len(NewFile
) - len(File
.replace("..\\", '').replace("../", '')) - 1]
538 # Last check the path with normal definitions
539 NewFile
= AllFiles
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
546 return NewRelaPath
, RelaPath
, File
549 def GetRelPath(Path1
, Path2
):
550 FileName
= os
.path
.basename(Path2
)
551 L1
= os
.path
.normpath(Path1
).split(os
.path
.normpath('/'))
552 L2
= os
.path
.normpath(Path2
).split(os
.path
.normpath('/'))
553 for Index
in range(0, len(L1
)):
554 if L1
[Index
] != L2
[Index
]:
555 FileName
= '../' * (len(L1
) - Index
)
556 for Index2
in range(Index
, len(L2
)):
557 FileName
= os
.path
.join(FileName
, L2
[Index2
])
559 return os
.path
.normpath(FileName
)
562 ## Get GUID value from given packages
564 # @param CName The CName of the GUID
565 # @param PackageList List of packages looking-up in
567 # @retval GuidValue if the CName is found in any given package
568 # @retval None if the CName is not found in all given packages
570 def GuidValue(CName
, PackageList
):
571 for P
in PackageList
:
573 return P
.Guids
[CName
]
576 ## Get Protocol value from given packages
578 # @param CName The CName of the GUID
579 # @param PackageList List of packages looking-up in
581 # @retval GuidValue if the CName is found in any given package
582 # @retval None if the CName is not found in all given packages
584 def ProtocolValue(CName
, PackageList
):
585 for P
in PackageList
:
586 if CName
in P
.Protocols
:
587 return P
.Protocols
[CName
]
590 ## Get PPI value from given packages
592 # @param CName The CName of the GUID
593 # @param PackageList List of packages looking-up in
595 # @retval GuidValue if the CName is found in any given package
596 # @retval None if the CName is not found in all given packages
598 def PpiValue(CName
, PackageList
):
599 for P
in PackageList
:
604 ## A string template class
606 # This class implements a template for string replacement. A string template
607 # looks like following
609 # ${BEGIN} other_string ${placeholder_name} other_string ${END}
611 # The string between ${BEGIN} and ${END} will be repeated as many times as the
612 # length of "placeholder_name", which is a list passed through a dict. The
613 # "placeholder_name" is the key name of the dict. The ${BEGIN} and ${END} can
614 # be not used and, in this case, the "placeholder_name" must not a list and it
615 # will just be replaced once.
617 class TemplateString(object):
618 _REPEAT_START_FLAG
= "BEGIN"
619 _REPEAT_END_FLAG
= "END"
621 class Section(object):
622 _LIST_TYPES
= [type([]), type(set()), type((0,))]
624 def __init__(self
, TemplateSection
, PlaceHolderList
):
625 self
._Template
= TemplateSection
626 self
._PlaceHolderList
= []
628 # Split the section into sub-sections according to the position of placeholders
630 self
._SubSectionList
= []
633 # The placeholders passed in must be in the format of
635 # PlaceHolderName, PlaceHolderStartPoint, PlaceHolderEndPoint
637 for PlaceHolder
,Start
,End
in PlaceHolderList
:
638 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:Start
])
639 self
._SubSectionList
.append(TemplateSection
[Start
:End
])
640 self
._PlaceHolderList
.append(PlaceHolder
)
641 SubSectionStart
= End
642 if SubSectionStart
< len(TemplateSection
):
643 self
._SubSectionList
.append(TemplateSection
[SubSectionStart
:])
645 self
._SubSectionList
= [TemplateSection
]
648 return self
._Template
+ " : " + str(self
._PlaceHolderList
)
650 def Instantiate(self
, PlaceHolderValues
):
652 RepeatPlaceHolders
= {}
653 NonRepeatPlaceHolders
= {}
655 for PlaceHolder
in self
._PlaceHolderList
:
656 if PlaceHolder
not in PlaceHolderValues
:
658 Value
= PlaceHolderValues
[PlaceHolder
]
659 if type(Value
) in self
._LIST
_TYPES
:
661 RepeatTime
= len(Value
)
662 elif RepeatTime
!= len(Value
):
666 "${%s} has different repeat time from others!" % PlaceHolder
,
667 ExtraData
=str(self
._Template
)
669 RepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
671 NonRepeatPlaceHolders
["${%s}" % PlaceHolder
] = Value
673 if NonRepeatPlaceHolders
:
675 for S
in self
._SubSectionList
:
676 if S
not in NonRepeatPlaceHolders
:
679 StringList
.append(str(NonRepeatPlaceHolders
[S
]))
681 StringList
= self
._SubSectionList
683 if RepeatPlaceHolders
:
685 for Index
in range(RepeatTime
):
687 if S
not in RepeatPlaceHolders
:
688 TempStringList
.append(S
)
690 TempStringList
.append(str(RepeatPlaceHolders
[S
][Index
]))
691 StringList
= TempStringList
693 return "".join(StringList
)
696 def __init__(self
, Template
=None):
698 self
.IsBinary
= False
699 self
._Template
= Template
700 self
._TemplateSectionList
= self
._Parse
(Template
)
704 # @retval string The string replaced
709 ## Split the template string into fragments per the ${BEGIN} and ${END} flags
711 # @retval list A list of TemplateString.Section objects
713 def _Parse(self
, Template
):
718 TemplateSectionList
= []
720 MatchObj
= gPlaceholderPattern
.search(Template
, SearchFrom
)
722 if MatchEnd
<= len(Template
):
723 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:], PlaceHolderList
)
724 TemplateSectionList
.append(TemplateSection
)
727 MatchString
= MatchObj
.group(1)
728 MatchStart
= MatchObj
.start()
729 MatchEnd
= MatchObj
.end()
731 if MatchString
== self
._REPEAT
_START
_FLAG
:
732 if MatchStart
> SectionStart
:
733 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
734 TemplateSectionList
.append(TemplateSection
)
735 SectionStart
= MatchEnd
737 elif MatchString
== self
._REPEAT
_END
_FLAG
:
738 TemplateSection
= TemplateString
.Section(Template
[SectionStart
:MatchStart
], PlaceHolderList
)
739 TemplateSectionList
.append(TemplateSection
)
740 SectionStart
= MatchEnd
743 PlaceHolderList
.append((MatchString
, MatchStart
- SectionStart
, MatchEnd
- SectionStart
))
744 SearchFrom
= MatchEnd
745 return TemplateSectionList
747 ## Replace the string template with dictionary of placeholders and append it to previous one
749 # @param AppendString The string template to append
750 # @param Dictionary The placeholder dictionaries
752 def Append(self
, AppendString
, Dictionary
=None):
754 SectionList
= self
._Parse
(AppendString
)
755 self
.String
+= "".join([S
.Instantiate(Dictionary
) for S
in SectionList
])
757 self
.String
+= AppendString
759 ## Replace the string template with dictionary of placeholders
761 # @param Dictionary The placeholder dictionaries
763 # @retval str The string replaced with placeholder values
765 def Replace(self
, Dictionary
=None):
766 return "".join([S
.Instantiate(Dictionary
) for S
in self
._TemplateSectionList
])
768 ## Progress indicator class
770 # This class makes use of thread to print progress on console.
773 # for avoiding deadloop
775 _ProgressThread
= None
776 _CheckInterval
= 0.25
780 # @param OpenMessage The string printed before progress charaters
781 # @param CloseMessage The string printed after progress charaters
782 # @param ProgressChar The charater used to indicate the progress
783 # @param Interval The interval in seconds between two progress charaters
785 def __init__(self
, OpenMessage
="", CloseMessage
="", ProgressChar
='.', Interval
=1.0):
786 self
.PromptMessage
= OpenMessage
787 self
.CodaMessage
= CloseMessage
788 self
.ProgressChar
= ProgressChar
789 self
.Interval
= Interval
790 if Progressor
._StopFlag
== None:
791 Progressor
._StopFlag
= threading
.Event()
793 ## Start to print progress charater
795 # @param OpenMessage The string printed before progress charaters
797 def Start(self
, OpenMessage
=None):
798 if OpenMessage
!= None:
799 self
.PromptMessage
= OpenMessage
800 Progressor
._StopFlag
.clear()
801 if Progressor
._ProgressThread
== None:
802 Progressor
._ProgressThread
= threading
.Thread(target
=self
._ProgressThreadEntry
)
803 Progressor
._ProgressThread
.setDaemon(False)
804 Progressor
._ProgressThread
.start()
806 ## Stop printing progress charater
808 # @param CloseMessage The string printed after progress charaters
810 def Stop(self
, CloseMessage
=None):
811 OriginalCodaMessage
= self
.CodaMessage
812 if CloseMessage
!= None:
813 self
.CodaMessage
= CloseMessage
815 self
.CodaMessage
= OriginalCodaMessage
817 ## Thread entry method
818 def _ProgressThreadEntry(self
):
819 sys
.stdout
.write(self
.PromptMessage
+ " ")
822 while not Progressor
._StopFlag
.isSet():
824 sys
.stdout
.write(self
.ProgressChar
)
826 TimeUp
= self
.Interval
827 time
.sleep(self
._CheckInterval
)
828 TimeUp
-= self
._CheckInterval
829 sys
.stdout
.write(" " + self
.CodaMessage
+ "\n")
832 ## Abort the progress display
835 if Progressor
._StopFlag
!= None:
836 Progressor
._StopFlag
.set()
837 if Progressor
._ProgressThread
!= None:
838 Progressor
._ProgressThread
.join()
839 Progressor
._ProgressThread
= None
841 ## A dict which can access its keys and/or values orderly
843 # The class implements a new kind of dict which its keys or values can be
844 # accessed in the order they are added into the dict. It guarantees the order
845 # by making use of an internal list to keep a copy of keys.
847 class sdict(IterableUserDict
):
850 IterableUserDict
.__init
__(self
)
854 def __setitem__(self
, key
, value
):
855 if key
not in self
._key
_list
:
856 self
._key
_list
.append(key
)
857 IterableUserDict
.__setitem
__(self
, key
, value
)
860 def __delitem__(self
, key
):
861 self
._key
_list
.remove(key
)
862 IterableUserDict
.__delitem
__(self
, key
)
864 ## used in "for k in dict" loop to ensure the correct order
866 return self
.iterkeys()
870 return len(self
._key
_list
)
873 def __contains__(self
, key
):
874 return key
in self
._key
_list
877 def index(self
, key
):
878 return self
._key
_list
.index(key
)
881 def insert(self
, key
, newkey
, newvalue
, order
):
882 index
= self
._key
_list
.index(key
)
883 if order
== 'BEFORE':
884 self
._key
_list
.insert(index
, newkey
)
885 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
886 elif order
== 'AFTER':
887 self
._key
_list
.insert(index
+ 1, newkey
)
888 IterableUserDict
.__setitem
__(self
, newkey
, newvalue
)
891 def append(self
, sdict
):
893 if key
not in self
._key
_list
:
894 self
._key
_list
.append(key
)
895 IterableUserDict
.__setitem
__(self
, key
, sdict
[key
])
897 def has_key(self
, key
):
898 return key
in self
._key
_list
903 IterableUserDict
.clear(self
)
905 ## Return a copy of keys
908 for key
in self
._key
_list
:
912 ## Return a copy of values
915 for key
in self
._key
_list
:
916 values
.append(self
[key
])
919 ## Return a copy of (key, value) list
922 for key
in self
._key
_list
:
923 items
.append((key
, self
[key
]))
928 return iter(self
.items())
930 ## Keys interation support
932 return iter(self
.keys())
934 ## Values interation support
935 def itervalues(self
):
936 return iter(self
.values())
938 ## Return value related to a key, and remove the (key, value) from the dict
939 def pop(self
, key
, *dv
):
941 if key
in self
._key
_list
:
943 self
.__delitem
__(key
)
948 ## Return (key, value) pair, and remove the (key, value) from the dict
950 key
= self
._key
_list
[-1]
952 self
.__delitem
__(key
)
955 def update(self
, dict=None, **kwargs
):
957 for k
, v
in dict.items():
960 for k
, v
in kwargs
.items():
963 ## Dictionary with restricted keys
967 def __init__(self
, KeyList
):
969 dict.__setitem
__(self
, Key
, "")
972 def __setitem__(self
, key
, value
):
974 EdkLogger
.error("RestrictedDict", ATTRIBUTE_SET_FAILURE
, "Key [%s] is not allowed" % key
,
975 ExtraData
=", ".join(dict.keys(self
)))
976 dict.__setitem
__(self
, key
, value
)
979 def __getitem__(self
, key
):
982 return dict.__getitem
__(self
, key
)
985 def __delitem__(self
, key
):
986 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="del")
991 self
.__setitem
__(Key
, "")
993 ## Return value related to a key, and remove the (key, value) from the dict
994 def pop(self
, key
, *dv
):
995 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="pop")
997 ## Return (key, value) pair, and remove the (key, value) from the dict
999 EdkLogger
.error("RestrictedDict", ATTRIBUTE_ACCESS_DENIED
, ExtraData
="popitem")
1001 ## Dictionary using prioritized list as key
1004 _ListType
= type([])
1005 _TupleType
= type(())
1006 _Wildcard
= 'COMMON'
1007 _ValidWildcardList
= ['COMMON', 'DEFAULT', 'ALL', '*', 'PLATFORM']
1009 def __init__(self
, _Single_
=False, _Level_
=2):
1010 self
._Level
_ = _Level_
1012 self
._Single
_ = _Single_
1015 def __getitem__(self
, key
):
1018 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1022 elif self
._Level
_ > 1:
1023 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1026 if self
._Level
_ > 1:
1027 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1029 if FirstKey
== None or str(FirstKey
).upper() in self
._ValidWildcardList
:
1030 FirstKey
= self
._Wildcard
1033 return self
._GetSingleValue
(FirstKey
, RestKeys
)
1035 return self
._GetAllValues
(FirstKey
, RestKeys
)
1037 def _GetSingleValue(self
, FirstKey
, RestKeys
):
1039 #print "%s-%s" % (FirstKey, self._Level_) ,
1040 if self
._Level
_ > 1:
1041 if FirstKey
== self
._Wildcard
:
1042 if FirstKey
in self
.data
:
1043 Value
= self
.data
[FirstKey
][RestKeys
]
1045 for Key
in self
.data
:
1046 Value
= self
.data
[Key
][RestKeys
]
1047 if Value
!= None: break
1049 if FirstKey
in self
.data
:
1050 Value
= self
.data
[FirstKey
][RestKeys
]
1051 if Value
== None and self
._Wildcard
in self
.data
:
1053 Value
= self
.data
[self
._Wildcard
][RestKeys
]
1055 if FirstKey
== self
._Wildcard
:
1056 if FirstKey
in self
.data
:
1057 Value
= self
.data
[FirstKey
]
1059 for Key
in self
.data
:
1060 Value
= self
.data
[Key
]
1061 if Value
!= None: break
1063 if FirstKey
in self
.data
:
1064 Value
= self
.data
[FirstKey
]
1065 elif self
._Wildcard
in self
.data
:
1066 Value
= self
.data
[self
._Wildcard
]
1069 def _GetAllValues(self
, FirstKey
, RestKeys
):
1071 if self
._Level
_ > 1:
1072 if FirstKey
== self
._Wildcard
:
1073 for Key
in self
.data
:
1074 Value
+= self
.data
[Key
][RestKeys
]
1076 if FirstKey
in self
.data
:
1077 Value
+= self
.data
[FirstKey
][RestKeys
]
1078 if self
._Wildcard
in self
.data
:
1079 Value
+= self
.data
[self
._Wildcard
][RestKeys
]
1081 if FirstKey
== self
._Wildcard
:
1082 for Key
in self
.data
:
1083 Value
.append(self
.data
[Key
])
1085 if FirstKey
in self
.data
:
1086 Value
.append(self
.data
[FirstKey
])
1087 if self
._Wildcard
in self
.data
:
1088 Value
.append(self
.data
[self
._Wildcard
])
1092 def __setitem__(self
, key
, value
):
1095 if KeyType
== self
._ListType
or KeyType
== self
._TupleType
:
1100 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1103 if self
._Level
_ > 1:
1104 RestKeys
= [self
._Wildcard
for i
in range(0, self
._Level
_-1)]
1106 if FirstKey
in self
._ValidWildcardList
:
1107 FirstKey
= self
._Wildcard
1109 if FirstKey
not in self
.data
and self
._Level
_ > 0:
1110 self
.data
[FirstKey
] = tdict(self
._Single
_, self
._Level
_ - 1)
1112 if self
._Level
_ > 1:
1113 self
.data
[FirstKey
][RestKeys
] = value
1115 self
.data
[FirstKey
] = value
1117 def SetGreedyMode(self
):
1118 self
._Single
_ = False
1119 if self
._Level
_ > 1:
1120 for Key
in self
.data
:
1121 self
.data
[Key
].SetGreedyMode()
1123 def SetSingleMode(self
):
1124 self
._Single
_ = True
1125 if self
._Level
_ > 1:
1126 for Key
in self
.data
:
1127 self
.data
[Key
].SetSingleMode()
1129 def GetKeys(self
, KeyIndex
=0):
1130 assert KeyIndex
>= 0
1132 return set(self
.data
.keys())
1135 for Key
in self
.data
:
1136 keys |
= self
.data
[Key
].GetKeys(KeyIndex
- 1)
1139 ## Boolean chain list
1141 class Blist(UserList
):
1142 def __init__(self
, initlist
=None):
1143 UserList
.__init
__(self
, initlist
)
1144 def __setitem__(self
, i
, item
):
1145 if item
not in [True, False]:
1151 def _GetResult(self
):
1153 for item
in self
.data
:
1156 Result
= property(_GetResult
)
1158 def ParseConsoleLog(Filename
):
1159 Opr
= open(os
.path
.normpath(Filename
), 'r')
1160 Opw
= open(os
.path
.normpath(Filename
+ '.New'), 'w+')
1161 for Line
in Opr
.readlines():
1162 if Line
.find('.efi') > -1:
1163 Line
= Line
[Line
.rfind(' ') : Line
.rfind('.efi')].strip()
1164 Opw
.write('%s\n' % Line
)
1171 # Analyze the pcd Value, Datum type and TokenNumber.
1172 # Used to avoid split issue while the value string contain "|" character
1174 # @param[in] Setting: A String contain value/datum type/token number information;
1176 # @retval ValueList: A List contain value, datum type and toke number.
1178 def AnalyzePcdData(Setting
):
1179 ValueList
= ['', '', '']
1181 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1182 PtrValue
= ValueRe
.findall(Setting
)
1184 ValueUpdateFlag
= False
1186 if len(PtrValue
) >= 1:
1187 Setting
= re
.sub(ValueRe
, '', Setting
)
1188 ValueUpdateFlag
= True
1190 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1191 ValueList
[0:len(TokenList
)] = TokenList
1194 ValueList
[0] = PtrValue
[0]
1198 ## AnalyzeHiiPcdData
1200 # Analyze the pcd Value, variable name, variable Guid and variable offset.
1201 # Used to avoid split issue while the value string contain "|" character
1203 # @param[in] Setting: A String contain VariableName, VariableGuid, VariableOffset, DefaultValue information;
1205 # @retval ValueList: A List contaian VariableName, VariableGuid, VariableOffset, DefaultValue.
1207 def AnalyzeHiiPcdData(Setting
):
1208 ValueList
= ['', '', '', '']
1210 ValueRe
= re
.compile(r
'^\s*L?\".*\|.*\"')
1211 PtrValue
= ValueRe
.findall(Setting
)
1213 ValueUpdateFlag
= False
1215 if len(PtrValue
) >= 1:
1216 Setting
= re
.sub(ValueRe
, '', Setting
)
1217 ValueUpdateFlag
= True
1219 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1220 ValueList
[0:len(TokenList
)] = TokenList
1223 ValueList
[0] = PtrValue
[0]
1227 ## AnalyzeVpdPcdData
1229 # Analyze the vpd pcd Value, Datum type and TokenNumber.
1230 # Used to avoid split issue while the value string contain "|" character
1232 # @param[in] Setting: A String contain value/datum type/token number information;
1234 # @retval ValueList: A List contain value, datum type and toke number.
1236 def AnalyzeVpdPcdData(Setting
):
1237 ValueList
= ['', '', '']
1239 ValueRe
= re
.compile(r
'\s*L?\".*\|.*\"\s*$')
1240 PtrValue
= ValueRe
.findall(Setting
)
1242 ValueUpdateFlag
= False
1244 if len(PtrValue
) >= 1:
1245 Setting
= re
.sub(ValueRe
, '', Setting
)
1246 ValueUpdateFlag
= True
1248 TokenList
= Setting
.split(TAB_VALUE_SPLIT
)
1249 ValueList
[0:len(TokenList
)] = TokenList
1252 ValueList
[2] = PtrValue
[0]
1256 ## check format of PCD value against its the datum type
1258 # For PCD value setting
1260 def CheckPcdDatum(Type
, Value
):
1262 if not (((Value
.startswith('L"') or Value
.startswith('"')) and Value
.endswith('"'))
1263 or (Value
.startswith('{') and Value
.endswith('}'))
1265 return False, "Invalid value [%s] of type [%s]; must be in the form of {...} for array"\
1266 ", or \"...\" for string, or L\"...\" for unicode string" % (Value
, Type
)
1267 elif Type
== 'BOOLEAN':
1268 if Value
not in ['TRUE', 'True', 'true', '0x1', '0x01', '1', 'FALSE', 'False', 'false', '0x0', '0x00', '0']:
1269 return False, "Invalid value [%s] of type [%s]; must be one of TRUE, True, true, 0x1, 0x01, 1"\
1270 ", FALSE, False, false, 0x0, 0x00, 0" % (Value
, Type
)
1271 elif type(Value
) == type(""):
1273 Value
= long(Value
, 0)
1275 return False, "Invalid value [%s] of type [%s];"\
1276 " must be a hexadecimal, decimal or octal in C language format."\
1281 ## Split command line option string to list
1283 # subprocess.Popen needs the args to be a sequence. Otherwise there's problem
1284 # in non-windows platform to launch command
1286 def SplitOption(OptionString
):
1291 for Index
in range(0, len(OptionString
)):
1292 CurrentChar
= OptionString
[Index
]
1293 if CurrentChar
in ['"', "'"]:
1294 if QuotationMark
== CurrentChar
:
1296 elif QuotationMark
== "":
1297 QuotationMark
= CurrentChar
1302 if CurrentChar
in ["/", "-"] and LastChar
in [" ", "\t", "\r", "\n"]:
1303 if Index
> OptionStart
:
1304 OptionList
.append(OptionString
[OptionStart
:Index
-1])
1306 LastChar
= CurrentChar
1307 OptionList
.append(OptionString
[OptionStart
:])
1310 def CommonPath(PathList
):
1311 P1
= min(PathList
).split(os
.path
.sep
)
1312 P2
= max(PathList
).split(os
.path
.sep
)
1313 for Index
in xrange(min(len(P1
), len(P2
))):
1314 if P1
[Index
] != P2
[Index
]:
1315 return os
.path
.sep
.join(P1
[:Index
])
1316 return os
.path
.sep
.join(P1
)
1318 class PathClass(object):
1319 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
1320 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', ToolCode
=''):
1322 self
.File
= str(File
)
1323 if os
.path
.isabs(self
.File
):
1327 self
.Root
= str(Root
)
1328 self
.AlterRoot
= str(AlterRoot
)
1330 # Remove any '.' and '..' in path
1332 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
1333 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
1334 # eliminate the side-effect of 'C:'
1335 if self
.Root
[-1] == ':':
1336 self
.Root
+= os
.path
.sep
1337 # file path should not start with path separator
1338 if self
.Root
[-1] == os
.path
.sep
:
1339 self
.File
= self
.Path
[len(self
.Root
):]
1341 self
.File
= self
.Path
[len(self
.Root
)+1:]
1343 self
.Path
= os
.path
.normpath(self
.File
)
1345 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
1346 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1350 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
1352 self
.Dir
= self
.Root
1354 self
.Dir
= self
.SubDir
1359 self
.Type
= self
.Ext
.lower()
1361 self
.IsBinary
= IsBinary
1362 self
.Target
= Target
1363 self
.TagName
= TagName
1364 self
.ToolCode
= ToolCode
1365 self
.ToolChainFamily
= ToolChainFamily
1369 ## Convert the object of this class to a string
1371 # Convert member Path of the class to a string
1373 # @retval string Formatted String
1378 ## Override __eq__ function
1380 # Check whether PathClass are the same
1382 # @retval False The two PathClass are different
1383 # @retval True The two PathClass are the same
1385 def __eq__(self
, Other
):
1386 if type(Other
) == type(self
):
1387 return self
.Path
== Other
.Path
1389 return self
.Path
== str(Other
)
1391 ## Override __hash__ function
1393 # Use Path as key in hash table
1395 # @retval string Key for hash table
1398 return hash(self
.Path
)
1400 def _GetFileKey(self
):
1401 if self
._Key
== None:
1402 self
._Key
= self
.Path
.upper() # + self.ToolChainFamily + self.TagName + self.ToolCode + self.Target
1405 def Validate(self
, Type
='', CaseSensitive
=True):
1406 if GlobalData
.gCaseInsensitive
:
1407 CaseSensitive
= False
1408 if Type
and Type
.lower() != self
.Type
:
1409 return FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % (self
.File
, Type
, self
.Type
)
1411 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
1412 if not RealRoot
and not RealFile
:
1413 RealFile
= self
.File
1415 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
1417 RealFile
= os
.path
.join(self
.Root
, self
.File
)
1418 return FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
1422 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
1423 if CaseSensitive
and (RealFile
!= self
.File
or (RealRoot
!= self
.Root
and RealRoot
!= self
.AlterRoot
)):
1424 ErrorCode
= FILE_CASE_MISMATCH
1425 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ " [in file system]"
1427 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
1428 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
1430 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
1433 self
.File
= RealFile
1434 self
.Root
= RealRoot
1435 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
1436 return ErrorCode
, ErrorInfo
1438 Key
= property(_GetFileKey
)
1440 ## Parse PE image to get the required PE informaion.
1442 class PeImageClass():
1445 # @param File FilePath of PeImage
1447 def __init__(self
, PeFile
):
1448 self
.FileName
= PeFile
1449 self
.IsValid
= False
1452 self
.SectionAlignment
= 0
1453 self
.SectionHeaderList
= []
1456 PeObject
= open(PeFile
, 'rb')
1458 self
.ErrorInfo
= self
.FileName
+ ' can not be found\n'
1461 ByteArray
= array
.array('B')
1462 ByteArray
.fromfile(PeObject
, 0x3E)
1463 ByteList
= ByteArray
.tolist()
1464 # DOS signature should be 'MZ'
1465 if self
._ByteListToStr
(ByteList
[0x0:0x2]) != 'MZ':
1466 self
.ErrorInfo
= self
.FileName
+ ' has no valid DOS signature MZ'
1469 # Read 4 byte PE Signature
1470 PeOffset
= self
._ByteListToInt
(ByteList
[0x3C:0x3E])
1471 PeObject
.seek(PeOffset
)
1472 ByteArray
= array
.array('B')
1473 ByteArray
.fromfile(PeObject
, 4)
1474 # PE signature should be 'PE\0\0'
1475 if ByteArray
.tostring() != 'PE\0\0':
1476 self
.ErrorInfo
= self
.FileName
+ ' has no valid PE signature PE00'
1479 # Read PE file header
1480 ByteArray
= array
.array('B')
1481 ByteArray
.fromfile(PeObject
, 0x14)
1482 ByteList
= ByteArray
.tolist()
1483 SecNumber
= self
._ByteListToInt
(ByteList
[0x2:0x4])
1485 self
.ErrorInfo
= self
.FileName
+ ' has no section header'
1488 # Read PE optional header
1489 OptionalHeaderSize
= self
._ByteListToInt
(ByteArray
[0x10:0x12])
1490 ByteArray
= array
.array('B')
1491 ByteArray
.fromfile(PeObject
, OptionalHeaderSize
)
1492 ByteList
= ByteArray
.tolist()
1493 self
.EntryPoint
= self
._ByteListToInt
(ByteList
[0x10:0x14])
1494 self
.SectionAlignment
= self
._ByteListToInt
(ByteList
[0x20:0x24])
1495 self
.Size
= self
._ByteListToInt
(ByteList
[0x38:0x3C])
1497 # Read each Section Header
1498 for Index
in range(SecNumber
):
1499 ByteArray
= array
.array('B')
1500 ByteArray
.fromfile(PeObject
, 0x28)
1501 ByteList
= ByteArray
.tolist()
1502 SecName
= self
._ByteListToStr
(ByteList
[0:8])
1503 SecVirtualSize
= self
._ByteListToInt
(ByteList
[8:12])
1504 SecRawAddress
= self
._ByteListToInt
(ByteList
[20:24])
1505 SecVirtualAddress
= self
._ByteListToInt
(ByteList
[12:16])
1506 self
.SectionHeaderList
.append((SecName
, SecVirtualAddress
, SecRawAddress
, SecVirtualSize
))
1510 def _ByteListToStr(self
, ByteList
):
1512 for index
in range(len(ByteList
)):
1513 if ByteList
[index
] == 0:
1515 String
+= chr(ByteList
[index
])
1518 def _ByteListToInt(self
, ByteList
):
1520 for index
in range(len(ByteList
) - 1, -1, -1):
1521 Value
= (Value
<< 8) |
int(ByteList
[index
])
1526 # This acts like the main() function for the script, unless it is 'import'ed into another
1529 if __name__
== '__main__':