2 # Common routines used by all tools
4 # Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
19 from os
import makedirs
22 from os
import listdir
25 from os
import linesep
27 from os
import environ
29 from collections
import OrderedDict
as Sdict
31 import Logger
.Log
as Logger
32 from Logger
import StringTable
as ST
33 from Logger
import ToolError
34 from Library
import GlobalData
35 from Library
.DataType
import SUP_MODULE_LIST
36 from Library
.DataType
import END_OF_LINE
37 from Library
.DataType
import TAB_SPLIT
38 from Library
.DataType
import TAB_LANGUAGE_EN_US
39 from Library
.DataType
import TAB_LANGUAGE_EN
40 from Library
.DataType
import TAB_LANGUAGE_EN_X
41 from Library
.DataType
import TAB_UNI_FILE_SUFFIXS
42 from Library
.StringUtils
import GetSplitValueList
43 from Library
.ParserValidate
import IsValidHexVersion
44 from Library
.ParserValidate
import IsValidPath
45 from Object
.POM
.CommonObject
import TextObject
46 from Core
.FileHook
import __FileHookOpen__
47 from Common
.MultipleWorkspace
import MultipleWorkspace
as mws
49 ## Convert GUID string in xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx style to C
52 # @param Guid: The GUID string
54 def GuidStringToGuidStructureString(Guid
):
55 GuidList
= Guid
.split('-')
57 for Index
in range(0, 3, 1):
58 Result
= Result
+ '0x' + GuidList
[Index
] + ', '
59 Result
= Result
+ '{0x' + GuidList
[3][0:2] + ', 0x' + GuidList
[3][2:4]
60 for Index
in range(0, 12, 2):
61 Result
= Result
+ ', 0x' + GuidList
[4][Index
:Index
+ 2]
65 ## Check whether GUID string is of format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
67 # @param GuidValue: The GUID value
69 def CheckGuidRegFormat(GuidValue
):
70 ## Regular expression used to find out register format of GUID
72 RegFormatGuidPattern
= re
.compile("^\s*([0-9a-fA-F]){8}-"
76 "([0-9a-fA-F]){12}\s*$")
78 if RegFormatGuidPattern
.match(GuidValue
):
84 ## Convert GUID string in C structure style to
85 # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
87 # @param GuidValue: The GUID value in C structure format
89 def GuidStructureStringToGuidString(GuidValue
):
90 GuidValueString
= GuidValue
.lower().replace("{", "").replace("}", "").\
91 replace(" ", "").replace(";", "")
92 GuidValueList
= GuidValueString
.split(",")
93 if len(GuidValueList
) != 11:
96 return "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x" % (
97 int(GuidValueList
[0], 16),
98 int(GuidValueList
[1], 16),
99 int(GuidValueList
[2], 16),
100 int(GuidValueList
[3], 16),
101 int(GuidValueList
[4], 16),
102 int(GuidValueList
[5], 16),
103 int(GuidValueList
[6], 16),
104 int(GuidValueList
[7], 16),
105 int(GuidValueList
[8], 16),
106 int(GuidValueList
[9], 16),
107 int(GuidValueList
[10], 16)
109 except BaseException
:
112 ## Create directories
114 # @param Directory: The directory name
116 def CreateDirectory(Directory
):
117 if Directory
is None or Directory
.strip() == "":
120 if not access(Directory
, F_OK
):
122 except BaseException
:
126 ## Remove directories, including files and sub-directories in it
128 # @param Directory: The directory name
130 def RemoveDirectory(Directory
, Recursively
=False):
131 if Directory
is None or Directory
.strip() == "" or not \
132 os
.path
.exists(Directory
):
135 CurrentDirectory
= getcwd()
137 for File
in listdir("."):
138 if os
.path
.isdir(File
):
139 RemoveDirectory(File
, Recursively
)
142 chdir(CurrentDirectory
)
145 ## Store content in file
147 # This method is used to save file only when its content is changed. This is
148 # quite useful for "make" system to decide what will be re-built and what
151 # @param File: The path of file
152 # @param Content: The new content of the file
153 # @param IsBinaryFile: The flag indicating if the file is binary file
156 def SaveFileOnChange(File
, Content
, IsBinaryFile
=True):
157 if os
.path
.exists(File
):
160 if Content
== __FileHookOpen__(File
, "rb").read():
162 except BaseException
:
163 Logger
.Error(None, ToolError
.FILE_OPEN_FAILURE
, ExtraData
=File
)
166 if Content
== __FileHookOpen__(File
, "r").read():
168 except BaseException
:
169 Logger
.Error(None, ToolError
.FILE_OPEN_FAILURE
, ExtraData
=File
)
171 CreateDirectory(os
.path
.dirname(File
))
174 FileFd
= __FileHookOpen__(File
, "wb")
175 FileFd
.write(Content
)
177 except BaseException
:
178 Logger
.Error(None, ToolError
.FILE_CREATE_FAILURE
, ExtraData
=File
)
181 FileFd
= __FileHookOpen__(File
, "w")
182 FileFd
.write(Content
)
184 except BaseException
:
185 Logger
.Error(None, ToolError
.FILE_CREATE_FAILURE
, ExtraData
=File
)
189 ## Get all files of a directory
191 # @param Root: Root dir
192 # @param SkipList : The files need be skipped
194 def GetFiles(Root
, SkipList
=None, FullPath
=True):
195 OriPath
= os
.path
.normpath(Root
)
197 for Root
, Dirs
, Files
in walk(Root
):
199 for Item
in SkipList
:
205 if Dir
.startswith('.'):
209 if File
.startswith('.'):
211 File
= os
.path
.normpath(os
.path
.join(Root
, File
))
213 File
= File
[len(OriPath
) + 1:]
214 FileList
.append(File
)
218 ## Get all non-metadata files of a directory
220 # @param Root: Root Dir
221 # @param SkipList : List of path need be skipped
222 # @param FullPath: True if the returned file should be full path
223 # @param PrefixPath: the path that need to be added to the files found
224 # @return: the list of files found
226 def GetNonMetaDataFiles(Root
, SkipList
, FullPath
, PrefixPath
):
227 FileList
= GetFiles(Root
, SkipList
, FullPath
)
229 for File
in FileList
:
230 ExtName
= os
.path
.splitext(File
)[1]
232 # skip '.dec', '.inf', '.dsc', '.fdf' files
234 if ExtName
.lower() not in ['.dec', '.inf', '.dsc', '.fdf']:
235 NewFileList
.append(os
.path
.normpath(os
.path
.join(PrefixPath
, File
)))
239 ## Check if given file exists or not
241 # @param File: File name or path to be checked
242 # @param Dir: The directory the file is relative to
244 def ValidFile(File
, Ext
=None):
245 File
= File
.replace('\\', '/')
247 FileExt
= os
.path
.splitext(File
)[1]
248 if FileExt
.lower() != Ext
.lower():
250 if not os
.path
.exists(File
):
256 # @param File: File name or path to be checked
257 # @param Dir: The directory the file is relative to
258 # @param OverrideDir: The override directory
260 def RealPath(File
, Dir
='', OverrideDir
=''):
261 NewFile
= os
.path
.normpath(os
.path
.join(Dir
, File
))
262 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
263 if not NewFile
and OverrideDir
:
264 NewFile
= os
.path
.normpath(os
.path
.join(OverrideDir
, File
))
265 NewFile
= GlobalData
.gALL_FILES
[NewFile
]
270 # @param File: File name or path to be checked
271 # @param Dir: The directory the file is relative to
272 # @param OverrideDir: The override directory
274 def RealPath2(File
, Dir
='', OverrideDir
=''):
276 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join\
277 (OverrideDir
, File
))]
279 if OverrideDir
[-1] == os
.path
.sep
:
280 return NewFile
[len(OverrideDir
):], NewFile
[0:len(OverrideDir
)]
282 return NewFile
[len(OverrideDir
) + 1:], \
283 NewFile
[0:len(OverrideDir
)]
285 NewFile
= GlobalData
.gALL_FILES
[os
.path
.normpath(os
.path
.join(Dir
, File
))]
288 if Dir
[-1] == os
.path
.sep
:
289 return NewFile
[len(Dir
):], NewFile
[0:len(Dir
)]
291 return NewFile
[len(Dir
) + 1:], NewFile
[0:len(Dir
)]
299 # @param PathList: PathList
301 def CommonPath(PathList
):
302 Path1
= min(PathList
).split(os
.path
.sep
)
303 Path2
= max(PathList
).split(os
.path
.sep
)
304 for Index
in range(min(len(Path1
), len(Path2
))):
305 if Path1
[Index
] != Path2
[Index
]:
306 return os
.path
.sep
.join(Path1
[:Index
])
307 return os
.path
.sep
.join(Path1
)
311 class PathClass(object):
312 def __init__(self
, File
='', Root
='', AlterRoot
='', Type
='', IsBinary
=False,
313 Arch
='COMMON', ToolChainFamily
='', Target
='', TagName
='', \
316 self
.File
= str(File
)
317 if os
.path
.isabs(self
.File
):
321 self
.Root
= str(Root
)
322 self
.AlterRoot
= str(AlterRoot
)
325 # Remove any '.' and '..' in path
328 self
.Path
= os
.path
.normpath(os
.path
.join(self
.Root
, self
.File
))
329 self
.Root
= os
.path
.normpath(CommonPath([self
.Root
, self
.Path
]))
331 # eliminate the side-effect of 'C:'
333 if self
.Root
[-1] == ':':
334 self
.Root
+= os
.path
.sep
336 # file path should not start with path separator
338 if self
.Root
[-1] == os
.path
.sep
:
339 self
.File
= self
.Path
[len(self
.Root
):]
341 self
.File
= self
.Path
[len(self
.Root
) + 1:]
343 self
.Path
= os
.path
.normpath(self
.File
)
345 self
.SubDir
, self
.Name
= os
.path
.split(self
.File
)
346 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
350 self
.Dir
= os
.path
.join(self
.Root
, self
.SubDir
)
354 self
.Dir
= self
.SubDir
359 self
.Type
= self
.Ext
.lower()
361 self
.IsBinary
= IsBinary
363 self
.TagName
= TagName
364 self
.ToolCode
= ToolCode
365 self
.ToolChainFamily
= ToolChainFamily
369 ## Convert the object of this class to a string
371 # Convert member Path of the class to a string
376 ## Override __eq__ function
378 # Check whether PathClass are the same
380 def __eq__(self
, Other
):
381 if isinstance(Other
, type(self
)):
382 return self
.Path
== Other
.Path
384 return self
.Path
== str(Other
)
386 ## Override __hash__ function
388 # Use Path as key in hash table
391 return hash(self
.Path
)
395 def _GetFileKey(self
):
396 if self
._Key
is None:
397 self
._Key
= self
.Path
.upper()
401 def Validate(self
, Type
='', CaseSensitive
=True):
402 if GlobalData
.gCASE_INSENSITIVE
:
403 CaseSensitive
= False
404 if Type
and Type
.lower() != self
.Type
:
405 return ToolError
.FILE_TYPE_MISMATCH
, '%s (expect %s but got %s)' % \
406 (self
.File
, Type
, self
.Type
)
408 RealFile
, RealRoot
= RealPath2(self
.File
, self
.Root
, self
.AlterRoot
)
409 if not RealRoot
and not RealFile
:
412 RealFile
= os
.path
.join(self
.AlterRoot
, self
.File
)
414 RealFile
= os
.path
.join(self
.Root
, self
.File
)
415 return ToolError
.FILE_NOT_FOUND
, os
.path
.join(self
.AlterRoot
, RealFile
)
419 if RealRoot
!= self
.Root
or RealFile
!= self
.File
:
420 if CaseSensitive
and (RealFile
!= self
.File
or \
421 (RealRoot
!= self
.Root
and RealRoot
!= \
423 ErrorCode
= ToolError
.FILE_CASE_MISMATCH
424 ErrorInfo
= self
.File
+ '\n\t' + RealFile
+ \
427 self
.SubDir
, self
.Name
= os
.path
.split(RealFile
)
428 self
.BaseName
, self
.Ext
= os
.path
.splitext(self
.Name
)
430 self
.Dir
= os
.path
.join(RealRoot
, self
.SubDir
)
435 self
.Path
= os
.path
.join(RealRoot
, RealFile
)
436 return ErrorCode
, ErrorInfo
438 Key
= property(_GetFileKey
)
440 ## Get current workspace
442 # get WORKSPACE from environment variable if present,if not use current working directory as WORKSPACE
448 if "WORKSPACE" in environ
:
449 WorkspaceDir
= os
.path
.normpath(environ
["WORKSPACE"])
450 if not os
.path
.exists(WorkspaceDir
):
452 ToolError
.UPT_ENVIRON_MISSING_ERROR
,
453 ST
.ERR_WORKSPACE_NOTEXIST
,
454 ExtraData
="%s" % WorkspaceDir
)
456 WorkspaceDir
= os
.getcwd()
458 if WorkspaceDir
[-1] == ':':
459 WorkspaceDir
+= os
.sep
461 PackagesPath
= os
.environ
.get("PACKAGES_PATH")
462 mws
.setWs(WorkspaceDir
, PackagesPath
)
464 return WorkspaceDir
, mws
.PACKAGES_PATH
468 # use full path and workspace to get relative path
469 # the destination of this function is mainly to resolve the root path issue(like c: or c:\)
471 # @param Fullpath: a string of fullpath
472 # @param Workspace: a string of workspace
474 def GetRelativePath(Fullpath
, Workspace
):
477 if Workspace
.endswith(os
.sep
):
478 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
):]
480 RelativePath
= Fullpath
[Fullpath
.upper().find(Workspace
.upper())+len(Workspace
)+1:]
484 ## Check whether all module types are in list
486 # check whether all module types (SUP_MODULE_LIST) are in list
488 # @param ModuleList: a list of ModuleType
490 def IsAllModuleList(ModuleList
):
491 NewModuleList
= [Module
.upper() for Module
in ModuleList
]
492 for Module
in SUP_MODULE_LIST
:
493 if Module
not in NewModuleList
:
498 ## Dictionary that use comment(GenericComment, TailComment) as value,
499 # if a new comment which key already in the dic is inserted, then the
500 # comment will be merged.
501 # Key is (Statement, SupArch), when TailComment is added, it will ident
502 # according to Statement
504 class MergeCommentDict(dict):
507 def __setitem__(self
, Key
, CommentVal
):
508 GenericComment
, TailComment
= CommentVal
510 OrigVal1
, OrigVal2
= dict.__getitem
__(self
, Key
)
512 dict.__setitem
__(self
, Key
, (OrigVal1
+ GenericComment
, OrigVal2 \
513 + len(Statement
) * ' ' + TailComment
))
515 dict.__setitem
__(self
, Key
, (GenericComment
, TailComment
))
519 def __getitem__(self
, Key
):
520 return dict.__getitem
__(self
, Key
)
523 ## GenDummyHelpTextObj
525 # @retval HelpTxt: Generated dummy help text object
527 def GenDummyHelpTextObj():
528 HelpTxt
= TextObject()
529 HelpTxt
.SetLang(TAB_LANGUAGE_EN_US
)
530 HelpTxt
.SetString(' ')
533 ## ConvertVersionToDecimal, the minor version should be within 0 - 99
534 # <HexVersion> ::= "0x" <Major> <Minor>
535 # <Major> ::= (a-fA-F0-9){4}
536 # <Minor> ::= (a-fA-F0-9){4}
537 # <DecVersion> ::= (0-65535) ["." (0-99)]
539 # @param StringIn: The string contains version defined in INF file.
540 # It can be Decimal or Hex
542 def ConvertVersionToDecimal(StringIn
):
543 if IsValidHexVersion(StringIn
):
544 Value
= int(StringIn
, 16)
546 Minor
= Value
& 0xFFFF
547 MinorStr
= str(Minor
)
548 if len(MinorStr
) == 1:
549 MinorStr
= '0' + MinorStr
550 return str(Major
) + '.' + MinorStr
552 if StringIn
.find(TAB_SPLIT
) != -1:
555 return StringIn
+ '.0'
558 # when StringIn is '', return it directly
562 ## GetHelpStringByRemoveHashKey
564 # Remove hash key at the header of string and return the remain.
566 # @param String: The string need to be processed.
568 def GetHelpStringByRemoveHashKey(String
):
570 PattenRemoveHashKey
= re
.compile(r
"^[#+\s]+", re
.DOTALL
)
571 String
= String
.strip()
575 LineList
= GetSplitValueList(String
, END_OF_LINE
)
576 for Line
in LineList
:
577 ValueList
= PattenRemoveHashKey
.split(Line
)
578 if len(ValueList
) == 1:
579 ReturnString
+= ValueList
[0] + END_OF_LINE
581 ReturnString
+= ValueList
[1] + END_OF_LINE
583 if ReturnString
.endswith('\n') and not ReturnString
.endswith('\n\n') and ReturnString
!= '\n':
584 ReturnString
= ReturnString
[:-1]
588 ## ConvPathFromAbsToRel
590 # Get relative file path from absolute path.
592 # @param Path: The string contain file absolute path.
593 # @param Root: The string contain the parent path of Path in.
596 def ConvPathFromAbsToRel(Path
, Root
):
597 Path
= os
.path
.normpath(Path
)
598 Root
= os
.path
.normpath(Root
)
599 FullPath
= os
.path
.normpath(os
.path
.join(Root
, Path
))
602 # If Path is absolute path.
603 # It should be in Root.
605 if os
.path
.isabs(Path
):
606 return FullPath
[FullPath
.find(Root
) + len(Root
) + 1:]
613 # Convert special characters to '_', '\' to '/'
614 # return converted path: Test!1.inf -> Test_1.inf
616 # @param Path: Path to be converted
618 def ConvertPath(Path
):
620 for Char
in Path
.strip():
621 if Char
.isalnum() or Char
in '.-_/':
622 RetPath
= RetPath
+ Char
624 RetPath
= RetPath
+ '/'
626 RetPath
= RetPath
+ '_'
631 # during install, convert the Spec string extract from UPD into INF allowable definition,
632 # the difference is period is allowed in the former (not the first letter) but not in the latter.
633 # return converted Spec string
635 # @param SpecStr: SpecStr to be converted
637 def ConvertSpec(SpecStr
):
640 if Char
.isalnum() or Char
== '_':
641 RetStr
= RetStr
+ Char
643 RetStr
= RetStr
+ '_'
650 # Judge two lists are identical(contain same item).
651 # The rule is elements in List A are in List B and elements in List B are in List A.
653 # @param ListA, ListB Lists need to be judged.
655 # @return True ListA and ListB are identical
656 # @return False ListA and ListB are different with each other
658 def IsEqualList(ListA
, ListB
):
663 if not ItemA
in ListB
:
667 if not ItemB
in ListA
:
674 # Convert item in ArchList if the start character is lower case.
675 # In UDP spec, Arch is only allowed as: [A-Z]([a-zA-Z0-9])*
677 # @param ArchList The ArchList need to be converted.
679 # @return NewList The ArchList been converted.
681 def ConvertArchList(ArchList
):
686 if isinstance(ArchList
, list):
687 for Arch
in ArchList
:
689 NewArchList
.append(Arch
)
690 elif isinstance(ArchList
, str):
691 ArchList
= ArchList
.upper()
692 NewArchList
.append(ArchList
)
696 ## ProcessLineExtender
698 # Process the LineExtender of Line in LineList.
699 # If one line ends with a line extender, then it will be combined together with next line.
701 # @param LineList The LineList need to be processed.
703 # @return NewList The ArchList been processed.
705 def ProcessLineExtender(LineList
):
708 while Count
< len(LineList
):
709 if LineList
[Count
].strip().endswith("\\") and Count
+ 1 < len(LineList
):
710 NewList
.append(LineList
[Count
].strip()[:-2] + LineList
[Count
+ 1])
713 NewList
.append(LineList
[Count
])
721 # Process EDK style comment in LineList: c style /* */ comment or cpp style // comment
724 # @param LineList The LineList need to be processed.
726 # @return LineList The LineList been processed.
727 # @return FirstPos Where Edk comment is first found, -1 if not found
729 def ProcessEdkComment(LineList
):
730 FindEdkBlockComment
= False
736 while(Count
< len(LineList
)):
737 Line
= LineList
[Count
].strip()
738 if Line
.startswith("/*"):
740 # handling c style comment
743 while Count
< len(LineList
):
744 Line
= LineList
[Count
].strip()
745 if Line
.endswith("*/"):
746 if (Count
== StartPos
) and Line
.strip() == '/*/':
750 FindEdkBlockComment
= True
754 if FindEdkBlockComment
:
757 for Index
in range(StartPos
, EndPos
+1):
759 FindEdkBlockComment
= False
760 elif Line
.find("//") != -1 and not Line
.startswith("#"):
762 # handling cpp style comment
764 LineList
[Count
] = Line
.replace("//", '#')
770 return LineList
, FirstPos
772 ## GetLibInstanceInfo
774 # Get the information from Library Instance INF file.
776 # @param string. A string start with # and followed by INF file path
777 # @param WorkSpace. The WorkSpace directory used to combined with INF file path.
779 # @return GUID, Version
780 def GetLibInstanceInfo(String
, WorkSpace
, LineNo
):
785 OriginalString
= String
786 String
= String
.strip()
790 # Remove "#" characters at the beginning
792 String
= GetHelpStringByRemoveHashKey(String
)
793 String
= String
.strip()
796 # Validate file name exist.
798 FullFileName
= os
.path
.normpath(os
.path
.realpath(os
.path
.join(WorkSpace
, String
)))
799 if not (ValidFile(FullFileName
)):
800 Logger
.Error("InfParser",
801 ToolError
.FORMAT_INVALID
,
802 ST
.ERR_FILELIST_EXIST
% (String
),
803 File
=GlobalData
.gINF_MODULE_NAME
,
805 ExtraData
=OriginalString
)
808 # Validate file exist/format.
810 if IsValidPath(String
, WorkSpace
):
811 IsValidFileFlag
= True
813 Logger
.Error("InfParser",
814 ToolError
.FORMAT_INVALID
,
815 ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
% (String
),
816 File
=GlobalData
.gINF_MODULE_NAME
,
818 ExtraData
=OriginalString
)
824 FInputfile
= open(FullFileName
, "r")
826 FileLinesList
= FInputfile
.readlines()
827 except BaseException
:
828 Logger
.Error("InfParser",
829 ToolError
.FILE_READ_FAILURE
,
830 ST
.ERR_FILE_OPEN_FAILURE
,
834 except BaseException
:
835 Logger
.Error("InfParser",
836 ToolError
.FILE_READ_FAILURE
,
837 ST
.ERR_FILE_OPEN_FAILURE
,
840 ReFileGuidPattern
= re
.compile("^\s*FILE_GUID\s*=.*$")
841 ReVerStringPattern
= re
.compile("^\s*VERSION_STRING\s*=.*$")
843 FileLinesList
= ProcessLineExtender(FileLinesList
)
845 for Line
in FileLinesList
:
846 if ReFileGuidPattern
.match(Line
):
847 FileGuidString
= Line
848 if ReVerStringPattern
.match(Line
):
852 FileGuidString
= GetSplitValueList(FileGuidString
, '=', 1)[1]
854 VerString
= GetSplitValueList(VerString
, '=', 1)[1]
856 return FileGuidString
, VerString
860 # Generate the local value for INF and DEC file. If Lang attribute not present, then use this value.
861 # If present, and there is no element without the Lang attribute, and one of the elements has the rfc1766 code is
862 # "en-x-tianocore", or "en-US" if "en-x-tianocore" was not found, or "en" if "en-US" was not found, or startswith 'en'
863 # if 'en' was not found, then use this value.
864 # If multiple entries of a tag exist which have the same language code, use the last entry.
866 # @param ValueList A list need to be processed.
867 # @param UseFirstValue: True to use the first value, False to use the last value
870 def GetLocalValue(ValueList
, UseFirstValue
=False):
876 for (Key
, Value
) in ValueList
:
877 if Key
== TAB_LANGUAGE_EN_X
:
883 if Key
== TAB_LANGUAGE_EN_US
:
889 if Key
== TAB_LANGUAGE_EN
:
895 if Key
.startswith(TAB_LANGUAGE_EN
):
922 ## GetCharIndexOutStr
924 # Get comment character index outside a string
926 # @param Line: The string to be checked
927 # @param CommentCharacter: Comment char, used to ignore comment content
931 def GetCharIndexOutStr(CommentCharacter
, Line
):
938 # Check whether comment character is in a string
941 for Index
in range(0, len(Line
)):
942 if Line
[Index
] == '"':
943 InString
= not InString
944 elif Line
[Index
] == CommentCharacter
and InString
:
946 elif Line
[Index
] == CommentCharacter
and (Index
+1) < len(Line
) and Line
[Index
+1] == CommentCharacter \
951 ## ValidateUNIFilePath
953 # Check the UNI file path
955 # @param FilePath: The UNI file path
957 def ValidateUNIFilePath(Path
):
958 Suffix
= Path
[Path
.rfind(TAB_SPLIT
):]
961 # Check if the suffix is one of the '.uni', '.UNI', '.Uni'
963 if Suffix
not in TAB_UNI_FILE_SUFFIXS
:
964 Logger
.Error("Unicode File Parser",
965 ToolError
.FORMAT_INVALID
,
966 Message
=ST
.ERR_UNI_FILE_SUFFIX_WRONG
,
970 # Check if '..' in the file name(without suffix)
972 if (TAB_SPLIT
+ TAB_SPLIT
) in Path
:
973 Logger
.Error("Unicode File Parser",
974 ToolError
.FORMAT_INVALID
,
975 Message
=ST
.ERR_UNI_FILE_NAME_INVALID
,
979 # Check if the file name is valid according to the DEC and INF specification
981 Pattern
= '[a-zA-Z0-9_][a-zA-Z0-9_\-\.]*'
982 FileName
= Path
.replace(Suffix
, '')
983 InvalidCh
= re
.sub(Pattern
, '', FileName
)
985 Logger
.Error("Unicode File Parser",
986 ToolError
.FORMAT_INVALID
,
987 Message
=ST
.ERR_INF_PARSER_FILE_NOT_EXIST_OR_NAME_INVALID
,