]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/UPT/Library/String.py
2 # This file is used to define common string related functions used in parsing
5 # Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
7 # This program and the accompanying materials are licensed and made available
8 # under the terms and conditions of the BSD License which accompanies this
9 # distribution. The full text of the license may be found at
10 # http://opensource.org/licenses/bsd-license.php
12 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 from string
import strip
24 import Logger
.Log
as Logger
25 import Library
.DataType
as DataType
26 from Logger
.ToolError
import FORMAT_INVALID
27 from Logger
.ToolError
import PARSER_ERROR
28 from Logger
import StringTable
as ST
31 # Regular expression for matching macro used in DSC/DEC/INF file inclusion
33 gMACRO_PATTERN
= re
.compile("\$\(([_A-Z][_A-Z0-9]*)\)", re
.UNICODE
)
37 # Get a value list from a string with multiple values splited with SplitTag
38 # The default SplitTag is DataType.TAB_VALUE_SPLIT
39 # 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']
41 # @param String: The input string to be splitted
42 # @param SplitTag: The split key, default is DataType.TAB_VALUE_SPLIT
43 # @param MaxSplit: The max number of split values, default is -1
46 def GetSplitValueList(String
, SplitTag
=DataType
.TAB_VALUE_SPLIT
, MaxSplit
=-1):
47 return map(lambda l
: l
.strip(), String
.split(SplitTag
, MaxSplit
))
51 # Find a key's all arches in dict, add the new arch to the list
52 # If not exist any arch, set the arch directly
54 # @param Dict: The input value for Dict
55 # @param Key: The input value for Key
56 # @param Arch: The Arch to be added or merged
58 def MergeArches(Dict
, Key
, Arch
):
59 if Key
in Dict
.keys():
60 Dict
[Key
].append(Arch
)
62 Dict
[Key
] = Arch
.split()
66 # Parse a string with format "DEFINE <VarName> = <PATH>"
67 # Generate a map Defines[VarName] = PATH
68 # Return False if invalid format
70 # @param String: String with DEFINE statement
71 # @param Arch: Supportted Arch
72 # @param Defines: DEFINE statement to be parsed
74 def GenDefines(String
, Arch
, Defines
):
75 if String
.find(DataType
.TAB_DEFINE
+ ' ') > -1:
76 List
= String
.replace(DataType
.TAB_DEFINE
+ ' ', '').\
77 split(DataType
.TAB_EQUAL_SPLIT
)
79 Defines
[(CleanString(List
[0]), Arch
)] = CleanString(List
[1])
85 ## GetLibraryClassesWithModuleType
87 # Get Library Class definition when no module type defined
89 # @param Lines: The content to be parsed
90 # @param Key: Reserved
91 # @param KeyValues: To store data after parsing
92 # @param CommentCharacter: Comment char, used to ignore comment content
94 def GetLibraryClassesWithModuleType(Lines
, Key
, KeyValues
, CommentCharacter
):
95 NewKey
= SplitModuleType(Key
)
96 Lines
= Lines
.split(DataType
.TAB_SECTION_END
, 1)[1]
97 LineList
= Lines
.splitlines()
99 Line
= CleanString(Line
, CommentCharacter
)
100 if Line
!= '' and Line
[0] != CommentCharacter
:
101 KeyValues
.append([CleanString(Line
, CommentCharacter
), NewKey
[1]])
109 # @param Lines: The content to be parsed
110 # @param Key: Reserved
111 # @param KeyValues: To store data after parsing
112 # @param CommentCharacter: Comment char, used to ignore comment content
114 def GetDynamics(Lines
, Key
, KeyValues
, CommentCharacter
):
116 # Get SkuId Name List
118 SkuIdNameList
= SplitModuleType(Key
)
120 Lines
= Lines
.split(DataType
.TAB_SECTION_END
, 1)[1]
121 LineList
= Lines
.splitlines()
122 for Line
in LineList
:
123 Line
= CleanString(Line
, CommentCharacter
)
124 if Line
!= '' and Line
[0] != CommentCharacter
:
125 KeyValues
.append([CleanString(Line
, CommentCharacter
), SkuIdNameList
[1]])
131 # Split ModuleType out of section defien to get key
132 # [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [
133 # 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ]
135 # @param Key: String to be parsed
137 def SplitModuleType(Key
):
138 KeyList
= Key
.split(DataType
.TAB_SPLIT
)
144 # Fill in for moduletype
148 KeyValue
= KeyList
[0]
150 KeyValue
= KeyValue
+ DataType
.TAB_SPLIT
+ KeyList
[1]
151 ReturnValue
.append(KeyValue
)
152 ReturnValue
.append(GetSplitValueList(KeyList
[2]))
156 ## Replace macro in string
158 # This method replace macros used in given string. The macros are given in a
161 # @param String String to be processed
162 # @param MacroDefinitions The macro definitions in the form of dictionary
163 # @param SelfReplacement To decide whether replace un-defined macro to ''
164 # @param Line: The content contain line string and line number
165 # @param FileName: The meta-file file name
167 def ReplaceMacro(String
, MacroDefinitions
= None, SelfReplacement
= False, Line
= None, FileName
= None, Flag
= False):
169 if MacroDefinitions
== None:
170 MacroDefinitions
= {}
171 while MacroDefinitions
:
172 QuotedStringList
= []
173 HaveQuotedMacroFlag
= False
175 MacroUsed
= gMACRO_PATTERN
.findall(String
)
177 ReQuotedString
= re
.compile('\"')
178 QuotedStringList
= ReQuotedString
.split(String
)
179 if len(QuotedStringList
) >= 3:
180 HaveQuotedMacroFlag
= True
183 for QuotedStringItem
in QuotedStringList
:
186 MacroString
+= QuotedStringItem
188 if Count
== len(QuotedStringList
) and Count
%2 == 0:
189 MacroString
+= QuotedStringItem
191 MacroUsed
= gMACRO_PATTERN
.findall(MacroString
)
193 # no macro found in String, stop replacing
195 if len(MacroUsed
) == 0:
197 for Macro
in MacroUsed
:
198 if Macro
not in MacroDefinitions
:
200 String
= String
.replace("$(%s)" % Macro
, '')
201 Logger
.Debug(5, "Delete undefined MACROs in file %s line %d: %s!" %(FileName
, Line
[1], Line
[0]))
203 if not HaveQuotedMacroFlag
:
204 String
= String
.replace("$(%s)" % Macro
, MacroDefinitions
[Macro
])
207 for QuotedStringItem
in QuotedStringList
:
210 QuotedStringList
[Count
-1] = QuotedStringList
[Count
-1].replace("$(%s)" % Macro
,
211 MacroDefinitions
[Macro
])
212 elif Count
== len(QuotedStringList
) and Count
%2 == 0:
213 QuotedStringList
[Count
-1] = QuotedStringList
[Count
-1].replace("$(%s)" % Macro
,
214 MacroDefinitions
[Macro
])
217 if HaveQuotedMacroFlag
:
219 for QuotedStringItem
in QuotedStringList
:
221 if Count
!= len(QuotedStringList
):
222 RetString
+= QuotedStringList
[Count
-1] + "\""
224 RetString
+= QuotedStringList
[Count
-1]
229 # in case there's macro not defined
231 if String
== LastString
:
239 # Create a normal path
240 # And replace DFEINE in the path
242 # @param Path: The input value for Path to be converted
243 # @param Defines: A set for DEFINE statement
245 def NormPath(Path
, Defines
= None):
246 IsRelativePath
= False
251 IsRelativePath
= True
253 # Replace with Define
256 Path
= ReplaceMacro(Path
, Defines
)
258 # To local path format
260 Path
= os
.path
.normpath(Path
)
262 if IsRelativePath
and Path
[0] != '.':
263 Path
= os
.path
.join('.', Path
)
268 # Remove comments in a string
271 # @param Line: The string to be cleaned
272 # @param CommentCharacter: Comment char, used to ignore comment content,
273 # default is DataType.TAB_COMMENT_SPLIT
275 def CleanString(Line
, CommentCharacter
=DataType
.TAB_COMMENT_SPLIT
, AllowCppStyleComment
=False):
281 # Replace EDK1's comment character
283 if AllowCppStyleComment
:
284 Line
= Line
.replace(DataType
.TAB_COMMENT_EDK1_SPLIT
, CommentCharacter
)
286 # remove comments, but we should escape comment character in string
289 for Index
in range(0, len(Line
)):
290 if Line
[Index
] == '"':
291 InString
= not InString
292 elif Line
[Index
] == CommentCharacter
and not InString
:
293 Line
= Line
[0: Index
]
296 # remove whitespace again
304 # Split comments in a string
307 # @param Line: The string to be cleaned
308 # @param CommentCharacter: Comment char, used to ignore comment content,
309 # default is DataType.TAB_COMMENT_SPLIT
311 def CleanString2(Line
, CommentCharacter
=DataType
.TAB_COMMENT_SPLIT
, AllowCppStyleComment
=False):
317 # Replace EDK1's comment character
319 if AllowCppStyleComment
:
320 Line
= Line
.replace(DataType
.TAB_COMMENT_EDK1_SPLIT
, CommentCharacter
)
322 # separate comments and statements
324 LineParts
= Line
.split(CommentCharacter
, 1)
326 # remove whitespace again
328 Line
= LineParts
[0].strip()
329 if len(LineParts
) > 1:
330 Comment
= LineParts
[1].strip()
332 # Remove prefixed and trailing comment characters
336 while Start
< End
and Comment
.startswith(CommentCharacter
, Start
, End
):
338 while End
>= 0 and Comment
.endswith(CommentCharacter
, Start
, End
):
340 Comment
= Comment
[Start
:End
]
341 Comment
= Comment
.strip()
347 ## GetMultipleValuesOfKeyFromLines
349 # Parse multiple strings to clean comment and spaces
350 # The result is saved to KeyValues
352 # @param Lines: The content to be parsed
353 # @param Key: Reserved
354 # @param KeyValues: To store data after parsing
355 # @param CommentCharacter: Comment char, used to ignore comment content
357 def GetMultipleValuesOfKeyFromLines(Lines
, Key
, KeyValues
, CommentCharacter
):
362 Lines
= Lines
.split(DataType
.TAB_SECTION_END
, 1)[1]
363 LineList
= Lines
.split('\n')
364 for Line
in LineList
:
365 Line
= CleanString(Line
, CommentCharacter
)
366 if Line
!= '' and Line
[0] != CommentCharacter
:
372 # Parse a DEFINE statement to get defined value
375 # @param String: The content to be parsed
376 # @param Key: The key of DEFINE statement
377 # @param CommentCharacter: Comment char, used to ignore comment content
379 def GetDefineValue(String
, Key
, CommentCharacter
):
382 String
= CleanString(String
)
383 return String
[String
.find(Key
+ ' ') + len(Key
+ ' ') : ]
385 ## GetSingleValueOfKeyFromLines
387 # Parse multiple strings as below to get value of each definition line
390 # The result is saved to Dictionary
392 # @param Lines: The content to be parsed
393 # @param Dictionary: To store data after parsing
394 # @param CommentCharacter: Comment char, be used to ignore comment content
395 # @param KeySplitCharacter: Key split char, between key name and key value.
396 # Key1 = Value1, '=' is the key split char
397 # @param ValueSplitFlag: Value split flag, be used to decide if has
399 # @param ValueSplitCharacter: Value split char, be used to split multiple
400 # values. Key1 = Value1|Value2, '|' is the value
403 def GetSingleValueOfKeyFromLines(Lines
, Dictionary
, CommentCharacter
, KeySplitCharacter
, \
404 ValueSplitFlag
, ValueSplitCharacter
):
405 Lines
= Lines
.split('\n')
413 # Handle DEFINE and SPEC
415 if Line
.find(DataType
.TAB_INF_DEFINES_DEFINE
+ ' ') > -1:
416 if '' in DefineValues
:
417 DefineValues
.remove('')
418 DefineValues
.append(GetDefineValue(Line
, DataType
.TAB_INF_DEFINES_DEFINE
, CommentCharacter
))
420 if Line
.find(DataType
.TAB_INF_DEFINES_SPEC
+ ' ') > -1:
422 SpecValues
.remove('')
423 SpecValues
.append(GetDefineValue(Line
, DataType
.TAB_INF_DEFINES_SPEC
, CommentCharacter
))
429 LineList
= Line
.split(KeySplitCharacter
, 1)
430 if len(LineList
) >= 2:
431 Key
= LineList
[0].split()
432 if len(Key
) == 1 and Key
[0][0] != CommentCharacter
:
434 # Remove comments and white spaces
436 LineList
[1] = CleanString(LineList
[1], CommentCharacter
)
438 Value
= map(strip
, LineList
[1].split(ValueSplitCharacter
))
440 Value
= CleanString(LineList
[1], CommentCharacter
).splitlines()
442 if Key
[0] in Dictionary
:
443 if Key
[0] not in Keys
:
444 Dictionary
[Key
[0]] = Value
447 Dictionary
[Key
[0]].extend(Value
)
449 Dictionary
[DataType
.TAB_INF_DEFINES_MACRO
][Key
[0]] = Value
[0]
451 if DefineValues
== []:
455 Dictionary
[DataType
.TAB_INF_DEFINES_DEFINE
] = DefineValues
456 Dictionary
[DataType
.TAB_INF_DEFINES_SPEC
] = SpecValues
460 ## The content to be parsed
462 # Do pre-check for a file before it is parsed
466 # @param FileName: Used for error report
467 # @param FileContent: File content to be parsed
468 # @param SupSectionTag: Used for error report
470 def PreCheck(FileName
, FileContent
, SupSectionTag
):
476 for Line
in FileContent
.splitlines():
481 Line
= CleanString(Line
)
483 # Remove commented line
485 if Line
.find(DataType
.TAB_COMMA_SPLIT
) == 0:
490 if Line
.find('$') > -1:
491 if Line
.find('$(') < 0 or Line
.find(')') < 0:
492 Logger
.Error("Parser", FORMAT_INVALID
, Line
=LineNo
, File
=FileName
, RaiseError
= Logger
.IS_RAISE_ERROR
)
496 if Line
.find('[') > -1 or Line
.find(']') > -1:
498 # Only get one '[' or one ']'
500 if not (Line
.find('[') > -1 and Line
.find(']') > -1):
501 Logger
.Error("Parser", FORMAT_INVALID
, Line
=LineNo
, File
=FileName
, RaiseError
= Logger
.IS_RAISE_ERROR
)
503 # Regenerate FileContent
505 NewFileContent
= NewFileContent
+ Line
+ '\r\n'
508 Logger
.Error("Parser", FORMAT_INVALID
, Line
=LineNo
, File
=FileName
, RaiseError
= Logger
.IS_RAISE_ERROR
)
510 return NewFileContent
514 # Check if the Filename is including ExtName
515 # Return True if it exists
516 # Raise a error message if it not exists
518 # @param CheckFilename: Name of the file to be checked
519 # @param ExtName: Ext name of the file to be checked
520 # @param ContainerFilename: The container file which describes the file to be
521 # checked, used for error report
522 # @param SectionName: Used for error report
523 # @param Line: The line in container file which defines the file
526 def CheckFileType(CheckFilename
, ExtName
, ContainerFilename
, SectionName
, Line
, LineNo
=-1):
527 if CheckFilename
!= '' and CheckFilename
!= None:
528 (Root
, Ext
) = os
.path
.splitext(CheckFilename
)
529 if Ext
.upper() != ExtName
.upper() and Root
:
530 ContainerFile
= open(ContainerFilename
, 'r').read()
532 LineNo
= GetLineNo(ContainerFile
, Line
)
533 ErrorMsg
= ST
.ERR_SECTIONNAME_INVALID
% (SectionName
, CheckFilename
, ExtName
)
534 Logger
.Error("Parser", PARSER_ERROR
, ErrorMsg
, Line
=LineNo
, \
535 File
=ContainerFilename
, RaiseError
=Logger
.IS_RAISE_ERROR
)
541 # Check if the file exists
542 # Return True if it exists
543 # Raise a error message if it not exists
545 # @param CheckFilename: Name of the file to be checked
546 # @param WorkspaceDir: Current workspace dir
547 # @param ContainerFilename: The container file which describes the file to
548 # be checked, used for error report
549 # @param SectionName: Used for error report
550 # @param Line: The line in container file which defines the
553 def CheckFileExist(WorkspaceDir
, CheckFilename
, ContainerFilename
, SectionName
, Line
, LineNo
=-1):
555 if CheckFilename
!= '' and CheckFilename
!= None:
556 CheckFile
= WorkspaceFile(WorkspaceDir
, CheckFilename
)
557 if not os
.path
.isfile(CheckFile
):
558 ContainerFile
= open(ContainerFilename
, 'r').read()
560 LineNo
= GetLineNo(ContainerFile
, Line
)
561 ErrorMsg
= ST
.ERR_CHECKFILE_NOTFOUND
% (CheckFile
, SectionName
)
562 Logger
.Error("Parser", PARSER_ERROR
, ErrorMsg
,
563 File
=ContainerFilename
, Line
= LineNo
, RaiseError
=Logger
.IS_RAISE_ERROR
)
568 # Find the index of a line in a file
570 # @param FileContent: Search scope
571 # @param Line: Search key
573 def GetLineNo(FileContent
, Line
, IsIgnoreComment
=True):
574 LineList
= FileContent
.splitlines()
575 for Index
in range(len(LineList
)):
576 if LineList
[Index
].find(Line
) > -1:
578 # Ignore statement in comment
581 if LineList
[Index
].strip()[0] == DataType
.TAB_COMMENT_SPLIT
:
589 # Raise a parser error
591 # @param Line: String which has error
592 # @param Section: Used for error report
593 # @param File: File which has the string
594 # @param Format: Correct format
596 def RaiseParserError(Line
, Section
, File
, Format
='', LineNo
=-1):
598 LineNo
= GetLineNo(open(os
.path
.normpath(File
), 'r').read(), Line
)
599 ErrorMsg
= ST
.ERR_INVALID_NOTFOUND
% (Line
, Section
)
601 Format
= "Correct format is " + Format
602 Logger
.Error("Parser", PARSER_ERROR
, ErrorMsg
, File
=File
, Line
=LineNo
, \
603 ExtraData
=Format
, RaiseError
=Logger
.IS_RAISE_ERROR
)
607 # Return a full path with workspace dir
609 # @param WorkspaceDir: Workspace dir
610 # @param Filename: Relative file name
612 def WorkspaceFile(WorkspaceDir
, Filename
):
613 return os
.path
.join(NormPath(WorkspaceDir
), NormPath(Filename
))
617 # Revmove '"' which startswith and endswith string
619 # @param String: The string need to be splited
621 def SplitString(String
):
622 if String
.startswith('\"'):
624 if String
.endswith('\"'):
628 ## Convert To Sql String
630 # Replace "'" with "''" in each item of StringList
632 # @param StringList: A list for strings to be converted
634 def ConvertToSqlString(StringList
):
635 return map(lambda s
: s
.replace("'", "''") , StringList
)
637 ## Convert To Sql String
639 # Replace "'" with "''" in the String
641 # @param String: A String to be converted
643 def ConvertToSqlString2(String
):
644 return String
.replace("'", "''")
646 ## RemoveBlockComment
648 # Remove comment block
650 # @param Lines: Block Comment Lines
652 def RemoveBlockComment(Lines
):
653 IsFindBlockComment
= False
660 # Remove comment block
662 if Line
.find(DataType
.TAB_COMMENT_EDK1_START
) > -1:
663 ReservedLine
= GetSplitList(Line
, DataType
.TAB_COMMENT_EDK1_START
, 1)[0]
664 IsFindBlockComment
= True
665 if Line
.find(DataType
.TAB_COMMENT_EDK1_END
) > -1:
666 Line
= ReservedLine
+ GetSplitList(Line
, DataType
.TAB_COMMENT_EDK1_END
, 1)[1]
668 IsFindBlockComment
= False
669 if IsFindBlockComment
:
672 NewLines
.append(Line
)
677 # Get String of a List
679 # @param Lines: string list
680 # @param Split: split character
682 def GetStringOfList(List
, Split
= ' '):
683 if type(List
) != type([]):
687 Str
= Str
+ Item
+ Split
692 # Get HelpTextList from HelpTextClassList
694 # @param HelpTextClassList: Help Text Class List
696 def GetHelpTextList(HelpTextClassList
):
698 if HelpTextClassList
:
699 for HelpText
in HelpTextClassList
:
700 if HelpText
.String
.endswith('\n'):
701 HelpText
.String
= HelpText
.String
[0: len(HelpText
.String
) - len('\n')]
702 List
.extend(HelpText
.String
.split('\n'))
705 ## Get String Array Length
707 # Get String Array Length
709 # @param String: the source string
711 def StringArrayLength(String
):
712 if isinstance(String
, unicode):
713 return (len(String
) + 1) * 2 + 1
714 elif String
.startswith('L"'):
715 return (len(String
) - 3 + 1) * 2
716 elif String
.startswith('"'):
717 return (len(String
) - 2 + 1)
719 return len(String
.split()) + 1
725 # @param OptionString: the option string
726 # @param Which: Which flag
727 # @param Against: Against flag
729 def RemoveDupOption(OptionString
, Which
="/I", Against
=None):
730 OptionList
= OptionString
.split()
734 for Index
in range(len(OptionList
)):
735 Opt
= OptionList
[Index
]
736 if not Opt
.startswith(Which
):
738 if len(Opt
) > len(Which
):
739 Val
= Opt
[len(Which
):]
743 OptionList
[Index
] = ""
745 ValueList
.append(Val
)
746 return " ".join(OptionList
)
748 ## Check if the string is HexDgit
750 # Return true if all characters in the string are digits and there is at
751 # least one character
752 # or valid Hexs (started with 0x, following by hexdigit letters)
754 # @param string: input string
761 if len(Str
) > 2 and Str
.upper().startswith('0X'):
769 ## Check if the string is HexDgit and its interger value within limit of UINT32
771 # Return true if all characters in the string are digits and there is at
772 # least one character
773 # or valid Hexs (started with 0x, following by hexdigit letters)
775 # @param string: input string
777 def IsHexDigitUINT32(Str
):
780 if (Value
<= 0xFFFFFFFF) and (Value
>= 0):
783 if len(Str
) > 2 and Str
.upper().startswith('0X'):
786 if (Value
<= 0xFFFFFFFF) and (Value
>= 0):
794 # The ASCII text files of type INF, DEC, INI are edited by developers,
795 # and may contain characters that cannot be directly translated to strings that
796 # are conformant with the UDP XML Schema. Any characters in this category
797 # (0x00-0x08, TAB [0x09], 0x0B, 0x0C, 0x0E-0x1F, 0x80-0xFF)
798 # must be converted to a space character[0x20] as part of the parsing process.
800 def ConvertSpecialChar(Lines
):
803 ReMatchSpecialChar
= re
.compile(r
"[\x00-\x08]|\x09|\x0b|\x0c|[\x0e-\x1f]|[\x7f-\xff]")
804 RetLines
.append(ReMatchSpecialChar
.sub(' ', line
))
810 # Assume Str is a valid feature flag expression.
811 # Return a list which contains tokens: alpha numeric token and other token
812 # Whitespace are not stripped
814 def __GetTokenList(Str
):
823 if Char
== '"' and PreChar
!= '\\':
824 InQuote
= not InQuote
829 if Token
and Token
!= 'L':
835 InQuote
= not InQuote
839 if not (Char
.isalnum() or Char
in '_'):
850 if PreChar
== '\\' and Char
== '\\':
862 # Convert NE operator to NOT EQ
863 # For example: 1 NE 2 -> 1 NOT EQ 2
865 # @param Expr: Feature flag expression to be converted
867 def ConvertNEToNOTEQ(Expr
):
868 List
= __GetTokenList(Expr
)
869 for Index
in range(len(List
)):
870 if List
[Index
] == 'NE':
871 List
[Index
] = 'NOT EQ'
876 # Convert NOT EQ operator to NE
877 # For example: 1 NOT NE 2 -> 1 NE 2
879 # @param Expr: Feature flag expression to be converted
881 def ConvertNOTEQToNE(Expr
):
882 List
= __GetTokenList(Expr
)
886 if HasNOT
and Token
== 'EQ':
887 # At least, 'NOT' is in the list
888 while not RetList
[-1].strip():
897 RetList
.append(Token
)
899 return ''.join(RetList
)
903 # Split an PCD entry string to Token.CName and PCD value and FFE.
904 # NOTE: PCD Value and FFE can contain "|" in it's expression. And in INF specification, have below rule.
905 # When using the characters "|" or "||" in an expression, the expression must be encapsulated in
906 # open "(" and close ")" parenthesis.
908 # @param String An PCD entry string need to be split.
910 # @return List [PcdTokenCName, Value, FFE]
912 def SplitPcdEntry(String
):
914 return ['', '',''], False
918 PcdFeatureFlagExp
= ''
920 ValueList
= GetSplitValueList(String
, "|", 1)
923 # Only contain TokenCName
925 if len(ValueList
) == 1:
926 return [ValueList
[0]], True
930 if len(ValueList
) == 2:
931 PcdTokenCName
= ValueList
[0]
932 ValueList
= GetSplitValueList(ValueList
[1], "|")
935 for Item
in ValueList
:
939 ParenthesisCount
+= 1
941 ParenthesisCount
-= 1
946 if RemainCount
== 0 and ParenthesisCount
>= 0:
947 NewValueList
.append(Item
)
948 RemainCount
= ParenthesisCount
949 elif RemainCount
> 0 and RemainCount
+ ParenthesisCount
>= 0:
950 NewValueList
[-1] = NewValueList
[-1] + '|' + Item
951 RemainCount
= RemainCount
+ ParenthesisCount
952 elif RemainCount
> 0 and RemainCount
+ ParenthesisCount
< 0:
956 return ['', '', ''], False
958 if len(NewValueList
) == 1:
959 PcdValue
= NewValueList
[0]
960 return [PcdTokenCName
, PcdValue
], True
961 elif len(NewValueList
) == 2:
962 PcdValue
= NewValueList
[0]
963 PcdFeatureFlagExp
= NewValueList
[1]
964 return [PcdTokenCName
, PcdValue
, PcdFeatureFlagExp
], True
966 return ['', '', ''], False
968 return ['', '', ''], False