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