]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Library/Misc.py
Sync BaseTool trunk (version r2649) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / Python / UPT / Library / Misc.py
1 ## @file
2 # Common routines used by all tools
3 #
4 # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
5 #
6 # This program and the accompanying materials are licensed and made available
7 # under the terms and conditions of the BSD License which accompanies this
8 # distribution. The full text of the license may be found at
9 # http://opensource.org/licenses/bsd-license.php
10 #
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 #
14
15 '''
16 Misc
17 '''
18
19 ##
20 # Import Modules
21 #
22 import os.path
23 from os import access
24 from os import F_OK
25 from os import makedirs
26 from os import getcwd
27 from os import chdir
28 from os import listdir
29 from os import remove
30 from os import rmdir
31 from os import linesep
32 from os import walk
33 from os import environ
34 import re
35 from UserDict import IterableUserDict
36
37 import Logger.Log as Logger
38 from Logger import StringTable as ST
39 from Logger import ToolError
40 from Library import GlobalData
41 from Library.DataType import SUP_MODULE_LIST
42 from Library.DataType import END_OF_LINE
43 from Library.DataType import TAB_SPLIT
44 from Library.DataType import LANGUAGE_EN_US
45 from Library.String import GetSplitValueList
46 from Library.ParserValidate import IsValidHexVersion
47 from Library.ParserValidate import IsValidPath
48 from Object.POM.CommonObject import TextObject
49
50 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C
51 # structure style
52 #
53 # @param Guid: The GUID string
54 #
55 def GuidStringToGuidStructureString(Guid):
56 GuidList = Guid.split('-')
57 Result = '{'
58 for Index in range(0, 3, 1):
59 Result = Result + '0x' + GuidList[Index] + ', '
60 Result = Result + '{0x' + GuidList[3][0:2] + ', 0x' + GuidList[3][2:4]
61 for Index in range(0, 12, 2):
62 Result = Result + ', 0x' + GuidList[4][Index:Index + 2]
63 Result += '}}'
64 return Result
65
66 ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
67 #
68 # @param GuidValue: The GUID value
69 #
70 def CheckGuidRegFormat(GuidValue):
71 ## Regular expression used to find out register format of GUID
72 #
73 RegFormatGuidPattern = re.compile("^\s*([0-9a-fA-F]){8}-"
74 "([0-9a-fA-F]){4}-"
75 "([0-9a-fA-F]){4}-"
76 "([0-9a-fA-F]){4}-"
77 "([0-9a-fA-F]){12}\s*$")
78
79 if RegFormatGuidPattern.match(GuidValue):
80 return True
81 else:
82 return False
83
84
85 ## Convert GUID string in C structure style to
86 # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
87 #
88 # @param GuidValue: The GUID value in C structure format
89 #
90 def GuidStructureStringToGuidString(GuidValue):
91 GuidValueString = GuidValue.lower().replace("{", "").replace("}", "").\
92 replace(" ", "").replace(";", "")
93 GuidValueList = GuidValueString.split(",")
94 if len(GuidValueList) != 11:
95 return ''
96 try:
97 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
98 int(GuidValueList[0], 16),
99 int(GuidValueList[1], 16),
100 int(GuidValueList[2], 16),
101 int(GuidValueList[3], 16),
102 int(GuidValueList[4], 16),
103 int(GuidValueList[5], 16),
104 int(GuidValueList[6], 16),
105 int(GuidValueList[7], 16),
106 int(GuidValueList[8], 16),
107 int(GuidValueList[9], 16),
108 int(GuidValueList[10], 16)
109 )
110 except BaseException:
111 return ''
112
113 ## Create directories
114 #
115 # @param Directory: The directory name
116 #
117 def CreateDirectory(Directory):
118 if Directory == None or Directory.strip() == "":
119 return True
120 try:
121 if not access(Directory, F_OK):
122 makedirs(Directory)
123 except BaseException:
124 return False
125 return True
126
127 ## Remove directories, including files and sub-directories in it
128 #
129 # @param Directory: The directory name
130 #
131 def RemoveDirectory(Directory, Recursively=False):
132 if Directory == None or Directory.strip() == "" or not \
133 os.path.exists(Directory):
134 return
135 if Recursively:
136 CurrentDirectory = getcwd()
137 chdir(Directory)
138 for File in listdir("."):
139 if os.path.isdir(File):
140 RemoveDirectory(File, Recursively)
141 else:
142 remove(File)
143 chdir(CurrentDirectory)
144 rmdir(Directory)
145
146 ## Store content in file
147 #
148 # This method is used to save file only when its content is changed. This is
149 # quite useful for "make" system to decide what will be re-built and what
150 # won't.
151 #
152 # @param File: The path of file
153 # @param Content: The new content of the file
154 # @param IsBinaryFile: The flag indicating if the file is binary file
155 # or not
156 #
157 def SaveFileOnChange(File, Content, IsBinaryFile=True):
158 if not IsBinaryFile:
159 Content = Content.replace("\n", linesep)
160
161 if os.path.exists(File):
162 try:
163 if Content == open(File, "rb").read():
164 return False
165 except BaseException:
166 Logger.Error(None, ToolError.FILE_OPEN_FAILURE, ExtraData=File)
167
168 CreateDirectory(os.path.dirname(File))
169 try:
170 FileFd = open(File, "wb")
171 FileFd.write(Content)
172 FileFd.close()
173 except BaseException:
174 Logger.Error(None, ToolError.FILE_CREATE_FAILURE, ExtraData=File)
175
176 return True
177
178 ## Get all files of a directory
179 #
180 # @param Root: Root dir
181 # @param SkipList : The files need be skipped
182 #
183 def GetFiles(Root, SkipList=None, FullPath=True):
184 OriPath = os.path.normpath(Root)
185 FileList = []
186 for Root, Dirs, Files in walk(Root):
187 if SkipList:
188 for Item in SkipList:
189 if Item in Dirs:
190 Dirs.remove(Item)
191 for Dir in Dirs:
192 if Dir.startswith('.'):
193 Dirs.remove(Dir)
194
195 for File in Files:
196 if File.startswith('.'):
197 continue
198 File = os.path.normpath(os.path.join(Root, File))
199 if not FullPath:
200 File = File[len(OriPath) + 1:]
201 FileList.append(File)
202
203 return FileList
204
205 ## Get all non-metadata files of a directory
206 #
207 # @param Root: Root Dir
208 # @param SkipList : List of path need be skipped
209 # @param FullPath: True if the returned file should be full path
210 # @param PrefixPath: the path that need to be added to the files found
211 # @return: the list of files found
212 #
213 def GetNonMetaDataFiles(Root, SkipList, FullPath, PrefixPath):
214 FileList = GetFiles(Root, SkipList, FullPath)
215 NewFileList = []
216 for File in FileList:
217 ExtName = os.path.splitext(File)[1]
218 #
219 # skip '.dec', '.inf', '.dsc', '.fdf' files
220 #
221 if ExtName.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
222 NewFileList.append(os.path.normpath(os.path.join(PrefixPath, File)))
223
224 return NewFileList
225
226 ## Check if given file exists or not
227 #
228 # @param File: File name or path to be checked
229 # @param Dir: The directory the file is relative to
230 #
231 def ValidFile(File, Ext=None):
232 File = File.replace('\\', '/')
233 if Ext != None:
234 FileExt = os.path.splitext(File)[1]
235 if FileExt.lower() != Ext.lower():
236 return False
237 if not os.path.exists(File):
238 return False
239 return True
240
241 ## RealPath
242 #
243 # @param File: File name or path to be checked
244 # @param Dir: The directory the file is relative to
245 # @param OverrideDir: The override directory
246 #
247 def RealPath(File, Dir='', OverrideDir=''):
248 NewFile = os.path.normpath(os.path.join(Dir, File))
249 NewFile = GlobalData.gALL_FILES[NewFile]
250 if not NewFile and OverrideDir:
251 NewFile = os.path.normpath(os.path.join(OverrideDir, File))
252 NewFile = GlobalData.gALL_FILES[NewFile]
253 return NewFile
254
255 ## RealPath2
256 #
257 # @param File: File name or path to be checked
258 # @param Dir: The directory the file is relative to
259 # @param OverrideDir: The override directory
260 #
261 def RealPath2(File, Dir='', OverrideDir=''):
262 if OverrideDir:
263 NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join\
264 (OverrideDir, File))]
265 if NewFile:
266 if OverrideDir[-1] == os.path.sep:
267 return NewFile[len(OverrideDir):], NewFile[0:len(OverrideDir)]
268 else:
269 return NewFile[len(OverrideDir) + 1:], \
270 NewFile[0:len(OverrideDir)]
271
272 NewFile = GlobalData.gALL_FILES[os.path.normpath(os.path.join(Dir, File))]
273 if NewFile:
274 if Dir:
275 if Dir[-1] == os.path.sep:
276 return NewFile[len(Dir):], NewFile[0:len(Dir)]
277 else:
278 return NewFile[len(Dir) + 1:], NewFile[0:len(Dir)]
279 else:
280 return NewFile, ''
281
282 return None, None
283
284 ## A dict which can access its keys and/or values orderly
285 #
286 # The class implements a new kind of dict which its keys or values can be
287 # accessed in the order they are added into the dict. It guarantees the order
288 # by making use of an internal list to keep a copy of keys.
289 #
290 class Sdict(IterableUserDict):
291 ## Constructor
292 #
293 def __init__(self):
294 IterableUserDict.__init__(self)
295 self._key_list = []
296
297 ## [] operator
298 #
299 def __setitem__(self, Key, Value):
300 if Key not in self._key_list:
301 self._key_list.append(Key)
302 IterableUserDict.__setitem__(self, Key, Value)
303
304 ## del operator
305 #
306 def __delitem__(self, Key):
307 self._key_list.remove(Key)
308 IterableUserDict.__delitem__(self, Key)
309
310 ## used in "for k in dict" loop to ensure the correct order
311 #
312 def __iter__(self):
313 return self.iterkeys()
314
315 ## len() support
316 #
317 def __len__(self):
318 return len(self._key_list)
319
320 ## "in" test support
321 #
322 def __contains__(self, Key):
323 return Key in self._key_list
324
325 ## indexof support
326 #
327 def index(self, Key):
328 return self._key_list.index(Key)
329
330 ## insert support
331 #
332 def insert(self, Key, Newkey, Newvalue, Order):
333 Index = self._key_list.index(Key)
334 if Order == 'BEFORE':
335 self._key_list.insert(Index, Newkey)
336 IterableUserDict.__setitem__(self, Newkey, Newvalue)
337 elif Order == 'AFTER':
338 self._key_list.insert(Index + 1, Newkey)
339 IterableUserDict.__setitem__(self, Newkey, Newvalue)
340
341 ## append support
342 #
343 def append(self, Sdict2):
344 for Key in Sdict2:
345 if Key not in self._key_list:
346 self._key_list.append(Key)
347 IterableUserDict.__setitem__(self, Key, Sdict2[Key])
348 ## hash key
349 #
350 def has_key(self, Key):
351 return Key in self._key_list
352
353 ## Empty the dict
354 #
355 def clear(self):
356 self._key_list = []
357 IterableUserDict.clear(self)
358
359 ## Return a copy of keys
360 #
361 def keys(self):
362 Keys = []
363 for Key in self._key_list:
364 Keys.append(Key)
365 return Keys
366
367 ## Return a copy of values
368 #
369 def values(self):
370 Values = []
371 for Key in self._key_list:
372 Values.append(self[Key])
373 return Values
374
375 ## Return a copy of (key, value) list
376 #
377 def items(self):
378 Items = []
379 for Key in self._key_list:
380 Items.append((Key, self[Key]))
381 return Items
382
383 ## Iteration support
384 #
385 def iteritems(self):
386 return iter(self.items())
387
388 ## Keys interation support
389 #
390 def iterkeys(self):
391 return iter(self.keys())
392
393 ## Values interation support
394 #
395 def itervalues(self):
396 return iter(self.values())
397
398 ## Return value related to a key, and remove the (key, value) from the dict
399 #
400 def pop(self, Key, *Dv):
401 Value = None
402 if Key in self._key_list:
403 Value = self[Key]
404 self.__delitem__(Key)
405 elif len(Dv) != 0 :
406 Value = Dv[0]
407 return Value
408
409 ## Return (key, value) pair, and remove the (key, value) from the dict
410 #
411 def popitem(self):
412 Key = self._key_list[-1]
413 Value = self[Key]
414 self.__delitem__(Key)
415 return Key, Value
416 ## update method
417 #
418 def update(self, Dict=None, **Kwargs):
419 if Dict != None:
420 for Key1, Val1 in Dict.items():
421 self[Key1] = Val1
422 if len(Kwargs):
423 for Key1, Val1 in Kwargs.items():
424 self[Key1] = Val1
425
426 ## CommonPath
427 #
428 # @param PathList: PathList
429 #
430 def CommonPath(PathList):
431 Path1 = min(PathList).split(os.path.sep)
432 Path2 = max(PathList).split(os.path.sep)
433 for Index in xrange(min(len(Path1), len(Path2))):
434 if Path1[Index] != Path2[Index]:
435 return os.path.sep.join(Path1[:Index])
436 return os.path.sep.join(Path1)
437
438 ## PathClass
439 #
440 class PathClass(object):
441 def __init__(self, File='', Root='', AlterRoot='', Type='', IsBinary=False,
442 Arch='COMMON', ToolChainFamily='', Target='', TagName='', \
443 ToolCode=''):
444 self.Arch = Arch
445 self.File = str(File)
446 if os.path.isabs(self.File):
447 self.Root = ''
448 self.AlterRoot = ''
449 else:
450 self.Root = str(Root)
451 self.AlterRoot = str(AlterRoot)
452
453 #
454 # Remove any '.' and '..' in path
455 #
456 if self.Root:
457 self.Path = os.path.normpath(os.path.join(self.Root, self.File))
458 self.Root = os.path.normpath(CommonPath([self.Root, self.Path]))
459 #
460 # eliminate the side-effect of 'C:'
461 #
462 if self.Root[-1] == ':':
463 self.Root += os.path.sep
464 #
465 # file path should not start with path separator
466 #
467 if self.Root[-1] == os.path.sep:
468 self.File = self.Path[len(self.Root):]
469 else:
470 self.File = self.Path[len(self.Root) + 1:]
471 else:
472 self.Path = os.path.normpath(self.File)
473
474 self.SubDir, self.Name = os.path.split(self.File)
475 self.BaseName, self.Ext = os.path.splitext(self.Name)
476
477 if self.Root:
478 if self.SubDir:
479 self.Dir = os.path.join(self.Root, self.SubDir)
480 else:
481 self.Dir = self.Root
482 else:
483 self.Dir = self.SubDir
484
485 if IsBinary:
486 self.Type = Type
487 else:
488 self.Type = self.Ext.lower()
489
490 self.IsBinary = IsBinary
491 self.Target = Target
492 self.TagName = TagName
493 self.ToolCode = ToolCode
494 self.ToolChainFamily = ToolChainFamily
495
496 self._Key = None
497
498 ## Convert the object of this class to a string
499 #
500 # Convert member Path of the class to a string
501 #
502 def __str__(self):
503 return self.Path
504
505 ## Override __eq__ function
506 #
507 # Check whether PathClass are the same
508 #
509 def __eq__(self, Other):
510 if type(Other) == type(self):
511 return self.Path == Other.Path
512 else:
513 return self.Path == str(Other)
514
515 ## Override __hash__ function
516 #
517 # Use Path as key in hash table
518 #
519 def __hash__(self):
520 return hash(self.Path)
521
522 ## _GetFileKey
523 #
524 def _GetFileKey(self):
525 if self._Key == None:
526 self._Key = self.Path.upper()
527 return self._Key
528 ## Validate
529 #
530 def Validate(self, Type='', CaseSensitive=True):
531 if GlobalData.gCASE_INSENSITIVE:
532 CaseSensitive = False
533 if Type and Type.lower() != self.Type:
534 return ToolError.FILE_TYPE_MISMATCH, '%s (expect %s but got %s)' % \
535 (self.File, Type, self.Type)
536
537 RealFile, RealRoot = RealPath2(self.File, self.Root, self.AlterRoot)
538 if not RealRoot and not RealFile:
539 RealFile = self.File
540 if self.AlterRoot:
541 RealFile = os.path.join(self.AlterRoot, self.File)
542 elif self.Root:
543 RealFile = os.path.join(self.Root, self.File)
544 return ToolError.FILE_NOT_FOUND, os.path.join(self.AlterRoot, RealFile)
545
546 ErrorCode = 0
547 ErrorInfo = ''
548 if RealRoot != self.Root or RealFile != self.File:
549 if CaseSensitive and (RealFile != self.File or \
550 (RealRoot != self.Root and RealRoot != \
551 self.AlterRoot)):
552 ErrorCode = ToolError.FILE_CASE_MISMATCH
553 ErrorInfo = self.File + '\n\t' + RealFile + \
554 " [in file system]"
555
556 self.SubDir, self.Name = os.path.split(RealFile)
557 self.BaseName, self.Ext = os.path.splitext(self.Name)
558 if self.SubDir:
559 self.Dir = os.path.join(RealRoot, self.SubDir)
560 else:
561 self.Dir = RealRoot
562 self.File = RealFile
563 self.Root = RealRoot
564 self.Path = os.path.join(RealRoot, RealFile)
565 return ErrorCode, ErrorInfo
566
567 Key = property(_GetFileKey)
568
569 ## Check environment variables
570 #
571 # Check environment variables that must be set for build. Currently they are
572 #
573 # WORKSPACE The directory all packages/platforms start from
574 # EDK_TOOLS_PATH The directory contains all tools needed by the build
575 # PATH $(EDK_TOOLS_PATH)/Bin/<sys> must be set in PATH
576 #
577 # If any of above environment variable is not set or has error, the build
578 # will be broken.
579 #
580 def CheckEnvVariable():
581 #
582 # check WORKSPACE
583 #
584 if "WORKSPACE" not in environ:
585 Logger.Error("UPT",
586 ToolError.UPT_ENVIRON_MISSING_ERROR,
587 ST.ERR_NOT_FOUND_ENVIRONMENT,
588 ExtraData="WORKSPACE")
589
590 WorkspaceDir = os.path.normpath(environ["WORKSPACE"])
591 if not os.path.exists(WorkspaceDir):
592 Logger.Error("UPT",
593 ToolError.UPT_ENVIRON_MISSING_ERROR,
594 ST.ERR_WORKSPACE_NOTEXIST,
595 ExtraData="%s" % WorkspaceDir)
596 elif ' ' in WorkspaceDir:
597 Logger.Error("UPT",
598 ToolError.FORMAT_NOT_SUPPORTED,
599 ST.ERR_SPACE_NOTALLOWED,
600 ExtraData=WorkspaceDir)
601
602 ## Check whether all module types are in list
603 #
604 # check whether all module types (SUP_MODULE_LIST) are in list
605 #
606 # @param ModuleList: a list of ModuleType
607 #
608 def IsAllModuleList(ModuleList):
609 NewModuleList = [Module.upper() for Module in ModuleList]
610 for Module in SUP_MODULE_LIST:
611 if Module not in NewModuleList:
612 return False
613 else:
614 return True
615
616 ## Dictionary that use comment(GenericComment, TailComment) as value,
617 # if a new comment which key already in the dic is inserted, then the
618 # comment will be merged.
619 # Key is (Statement, SupArch), when TailComment is added, it will ident
620 # according to Statement
621 #
622 class MergeCommentDict(dict):
623 ## []= operator
624 #
625 def __setitem__(self, Key, CommentVal):
626 GenericComment, TailComment = CommentVal
627 if Key in self:
628 OrigVal1, OrigVal2 = dict.__getitem__(self, Key)
629 Statement = Key[0]
630 dict.__setitem__(self, Key, (OrigVal1 + GenericComment, OrigVal2 \
631 + len(Statement) * ' ' + TailComment))
632 else:
633 dict.__setitem__(self, Key, (GenericComment, TailComment))
634
635 ## =[] operator
636 #
637 def __getitem__(self, Key):
638 return dict.__getitem__(self, Key)
639
640
641 ## GenDummyHelpTextObj
642 #
643 # @retval HelpTxt: Generated dummy help text object
644 #
645 def GenDummyHelpTextObj():
646 HelpTxt = TextObject()
647 HelpTxt.SetLang(LANGUAGE_EN_US)
648 HelpTxt.SetString(' ')
649 return HelpTxt
650
651 ## ConvertVersionToDecimal, the minor version should be within 0 - 99
652 # <HexVersion> ::= "0x" <Major> <Minor>
653 # <Major> ::= (a-fA-F0-9){4}
654 # <Minor> ::= (a-fA-F0-9){4}
655 # <DecVersion> ::= (0-65535) ["." (0-99)]
656 #
657 # @param StringIn: The string contains version defined in INF file.
658 # It can be Decimal or Hex
659 #
660 def ConvertVersionToDecimal(StringIn):
661 if IsValidHexVersion(StringIn):
662 Value = int(StringIn, 16)
663 Major = Value >> 16
664 Minor = Value & 0xFFFF
665 MinorStr = str(Minor)
666 if len(MinorStr) == 1:
667 MinorStr = '0' + MinorStr
668 return str(Major) + '.' + MinorStr
669 else:
670 if StringIn.find(TAB_SPLIT) != -1:
671 return StringIn
672 elif StringIn:
673 return StringIn + '.0'
674 else:
675 #
676 # when StringIn is '', return it directly
677 #
678 return StringIn
679
680 ## GetHelpStringByRemoveHashKey
681 #
682 # Remove hash key at the header of string and return the remain.
683 #
684 # @param String: The string need to be processed.
685 #
686 def GetHelpStringByRemoveHashKey(String):
687 ReturnString = ''
688 PattenRemoveHashKey = re.compile(r"^[#+\s]+", re.DOTALL)
689 String = String.strip()
690 if String == '':
691 return String
692
693 LineList = GetSplitValueList(String, END_OF_LINE)
694 for Line in LineList:
695 ValueList = PattenRemoveHashKey.split(Line)
696 if len(ValueList) == 1:
697 ReturnString += ValueList[0] + END_OF_LINE
698 else:
699 ReturnString += ValueList[1] + END_OF_LINE
700
701 if ReturnString.endswith('\n') and not ReturnString.endswith('\n\n') and ReturnString != '\n':
702 ReturnString = ReturnString[:-1]
703
704 return ReturnString
705
706 ## ConvPathFromAbsToRel
707 #
708 # Get relative file path from absolute path.
709 #
710 # @param Path: The string contain file absolute path.
711 # @param Root: The string contain the parent path of Path in.
712 #
713 #
714 def ConvPathFromAbsToRel(Path, Root):
715 Path = os.path.normpath(Path)
716 Root = os.path.normpath(Root)
717 FullPath = os.path.normpath(os.path.join(Root, Path))
718
719 #
720 # If Path is absolute path.
721 # It should be in Root.
722 #
723 if os.path.isabs(Path):
724 return FullPath[FullPath.find(Root) + len(Root) + 1:]
725
726 else:
727 return Path
728
729 ## ConvertPath
730 #
731 # Convert special characters to '_', '\' to '/'
732 # return converted path: Test!1.inf -> Test_1.inf
733 #
734 # @param Path: Path to be converted
735 #
736 def ConvertPath(Path):
737 RetPath = ''
738 for Char in Path.strip():
739 if Char.isalnum() or Char in '.-_/':
740 RetPath = RetPath + Char
741 elif Char == '\\':
742 RetPath = RetPath + '/'
743 else:
744 RetPath = RetPath + '_'
745 return RetPath
746
747 ## ConvertSpec
748 #
749 # during install, convert the Spec string extract from UPD into INF allowable definition,
750 # the difference is period is allowed in the former (not the first letter) but not in the latter.
751 # return converted Spec string
752 #
753 # @param SpecStr: SpecStr to be converted
754 #
755 def ConvertSpec(SpecStr):
756 RetStr = ''
757 for Char in SpecStr:
758 if Char.isalnum() or Char == '_':
759 RetStr = RetStr + Char
760 else:
761 RetStr = RetStr + '_'
762
763 return RetStr
764
765
766 ## IsEqualList
767 #
768 # Judge two lists are identical(contain same item).
769 # The rule is elements in List A are in List B and elements in List B are in List A.
770 #
771 # @param ListA, ListB Lists need to be judged.
772 #
773 # @return True ListA and ListB are identical
774 # @return False ListA and ListB are different with each other
775 #
776 def IsEqualList(ListA, ListB):
777 if ListA == ListB:
778 return True
779
780 for ItemA in ListA:
781 if not ItemA in ListB:
782 return False
783
784 for ItemB in ListB:
785 if not ItemB in ListA:
786 return False
787
788 return True
789
790 ## ConvertArchList
791 #
792 # Convert item in ArchList if the start character is lower case.
793 # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
794 #
795 # @param ArchList The ArchList need to be converted.
796 #
797 # @return NewList The ArchList been converted.
798 #
799 def ConvertArchList(ArchList):
800 NewArchList = []
801 if not ArchList:
802 return NewArchList
803
804 if type(ArchList) == list:
805 for Arch in ArchList:
806 Arch = Arch.upper()
807 NewArchList.append(Arch)
808 elif type(ArchList) == str:
809 ArchList = ArchList.upper()
810 NewArchList.append(ArchList)
811
812 return NewArchList
813
814 ## ProcessLineExtender
815 #
816 # Process the LineExtender of Line in LineList.
817 # If one line ends with a line extender, then it will be combined together with next line.
818 #
819 # @param LineList The LineList need to be processed.
820 #
821 # @return NewList The ArchList been processed.
822 #
823 def ProcessLineExtender(LineList):
824 NewList = []
825 Count = 0
826 while Count < len(LineList):
827 if LineList[Count].strip().endswith("\\") and Count + 1 < len(LineList):
828 NewList.append(LineList[Count].strip()[:-2] + LineList[Count + 1])
829 Count = Count + 1
830 else:
831 NewList.append(LineList[Count])
832
833 Count = Count + 1
834
835 return NewList
836
837 ## ProcessEdkComment
838 #
839 # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
840 #
841 #
842 # @param LineList The LineList need to be processed.
843 #
844 # @return LineList The LineList been processed.
845 # @return FirstPos Where Edk comment is first found, -1 if not found
846 #
847 def ProcessEdkComment(LineList):
848 FindEdkBlockComment = False
849 Count = 0
850 StartPos = -1
851 EndPos = -1
852 FirstPos = -1
853
854 while(Count < len(LineList)):
855 Line = LineList[Count].strip()
856 if Line.startswith("/*"):
857 #
858 # handling c style comment
859 #
860 StartPos = Count
861 while Count < len(LineList):
862 Line = LineList[Count].strip()
863 if Line.endswith("*/"):
864 if (Count == StartPos) and Line.strip() == '/*/':
865 Count = Count + 1
866 continue
867 EndPos = Count
868 FindEdkBlockComment = True
869 break
870 Count = Count + 1
871
872 if FindEdkBlockComment:
873 if FirstPos == -1:
874 FirstPos = StartPos
875 for Index in xrange(StartPos, EndPos+1):
876 LineList[Index] = ''
877 FindEdkBlockComment = False
878 elif Line.find("//") != -1 and not Line.startswith("#"):
879 #
880 # handling cpp style comment
881 #
882 LineList[Count] = Line.replace("//", '#')
883 if FirstPos == -1:
884 FirstPos = Count
885
886 Count = Count + 1
887
888 return LineList, FirstPos
889
890 ## GetLibInstanceInfo
891 #
892 # Get the information from Library Instance INF file.
893 #
894 # @param string. A string start with # and followed by INF file path
895 # @param WorkSpace. The WorkSpace directory used to combined with INF file path.
896 #
897 # @return GUID, Version
898 def GetLibInstanceInfo(String, WorkSpace, LineNo):
899
900 FileGuidString = ""
901 VerString = ""
902
903 OrignalString = String
904 String = String.strip()
905 if not String:
906 return None, None
907 #
908 # Remove "#" characters at the beginning
909 #
910 String = GetHelpStringByRemoveHashKey(String)
911 String = String.strip()
912
913 #
914 # Validate file name exist.
915 #
916 FullFileName = os.path.normpath(os.path.realpath(os.path.join(WorkSpace, String)))
917 if not (ValidFile(FullFileName)):
918 Logger.Error("InfParser",
919 ToolError.FORMAT_INVALID,
920 ST.ERR_FILELIST_EXIST % (String),
921 File=GlobalData.gINF_MODULE_NAME,
922 Line=LineNo,
923 ExtraData=OrignalString)
924
925 #
926 # Validate file exist/format.
927 #
928 if IsValidPath(String, WorkSpace):
929 IsValidFileFlag = True
930 else:
931 Logger.Error("InfParser",
932 ToolError.FORMAT_INVALID,
933 ST.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID % (String),
934 File=GlobalData.gINF_MODULE_NAME,
935 Line=LineNo,
936 ExtraData=OrignalString)
937 return False
938 if IsValidFileFlag:
939 FileLinesList = []
940
941 try:
942 FInputfile = open(FullFileName, "rb", 0)
943 try:
944 FileLinesList = FInputfile.readlines()
945 except BaseException:
946 Logger.Error("InfParser",
947 ToolError.FILE_READ_FAILURE,
948 ST.ERR_FILE_OPEN_FAILURE,
949 File=FullFileName)
950 finally:
951 FInputfile.close()
952 except BaseException:
953 Logger.Error("InfParser",
954 ToolError.FILE_READ_FAILURE,
955 ST.ERR_FILE_OPEN_FAILURE,
956 File=FullFileName)
957
958 ReFileGuidPattern = re.compile("^\s*FILE_GUID\s*=.*$")
959 ReVerStringPattern = re.compile("^\s*VERSION_STRING\s*=.*$")
960
961 FileLinesList = ProcessLineExtender(FileLinesList)
962
963 for Line in FileLinesList:
964 if ReFileGuidPattern.match(Line):
965 FileGuidString = Line
966 if ReVerStringPattern.match(Line):
967 VerString = Line
968
969 if FileGuidString:
970 FileGuidString = GetSplitValueList(FileGuidString, '=', 1)[1]
971 if VerString:
972 VerString = GetSplitValueList(VerString, '=', 1)[1]
973
974 return FileGuidString, VerString