1## @file
2# This file is used to define common parsing related functions used in parsing INF/DEC/DSC process
3#
4# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5# SPDX-License-Identifier: BSD-2-Clause-Patent
6#
7
8##
9# Import Modules
10#
11from __future__ import absolute_import
12from .StringUtils import *
13from CommonDataClass.DataClass import *
14from .DataType import *
15
16## ParseDefineMacro
17#
18# Search whole table to find all defined Macro and replaced them with the real values
19#
20def ParseDefineMacro2(Table, RecordSets, GlobalMacro):
21    Macros = {}
22    #
23    # Find all DEFINE macros in section [Header] and its section
24    #
25    SqlCommand = """select Value1, Value2, BelongsToItem, StartLine, Arch from %s
26                    where Model = %s
27                    and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE)
28    RecordSet = Table.Exec(SqlCommand)
29    for Record in RecordSet:
30        Macros[Record[0]] = Record[1]
31
32    #
33    # Overridden by Global Macros
34    #
35    Macros.update(GlobalMacro)
36
37    #
38    # Replace the Macros
39    #
40    for Value in (v for v in RecordSets.values() if v):
41        for Item in Value:
42            Item[0] = ReplaceMacro(Item[0], Macros)
43
44## ParseDefineMacro
45#
46# Search whole table to find all defined Macro and replaced them with the real values
47#
48def ParseDefineMacro(Table, GlobalMacro):
49    Macros = {}
50    #
51    # Find all DEFINE macros
52    #
53    SqlCommand = """select Value1, Value2, BelongsToItem, StartLine, Arch from %s
54                    where Model = %s
55                    and Enabled > -1""" % (Table.Table, MODEL_META_DATA_DEFINE)
56    RecordSet = Table.Exec(SqlCommand)
57    for Record in RecordSet:
58#***************************************************************************************************************************************************
59#            The follow SqlCommand (expr replace) is not supported in Sqlite 3.3.4 which is used in Python 2.5                                     *
60#            Reserved Only                                                                                                                         *
61#            SqlCommand = """update %s set Value1 = replace(Value1, '%s', '%s')                                                                    *
62#                            where ID in (select ID from %s                                                                                        *
63#                                         where Model = %s                                                                                         *
64#                                         and Value1 like '%%%s%%'                                                                                 *
65#                                         and StartLine > %s                                                                                       *
66#                                         and Enabled > -1                                                                                         *
67#                                         and Arch = '%s')""" % \                                                                                  *
68#                                         (self.TblDsc.Table, Record[0], Record[1], self.TblDsc.Table, Record[2], Record[1], Record[3], Record[4]) *
69#***************************************************************************************************************************************************
70        Macros[Record[0]] = Record[1]
71
72    #
73    # Overridden by Global Macros
74    #
75    Macros.update(GlobalMacro)
76
77    #
78    # Found all defined macro and replaced
79    #
80    SqlCommand = """select ID, Value1 from %s
81                    where Model != %s
82                    and Value1 like '%%$(%%' and Value1 like '%%)%%'
83                    and Enabled > -1"""  % (Table.Table, MODEL_META_DATA_DEFINE)
84    FoundRecords = Table.Exec(SqlCommand)
85    for FoundRecord in FoundRecords:
86        NewValue = ReplaceMacro(FoundRecord[1], Macros)
87        SqlCommand = """update %s set Value1 = '%s'
88                        where ID = %s""" % (Table.Table, ConvertToSqlString2(NewValue), FoundRecord[0])
89        Table.Exec(SqlCommand)
90
91##QueryDefinesItem
92#
93# Search item of section [Defines] by name, return its values
94#
95# @param Table: The Table to be executed
96# @param Name:  The Name of item of section [Defines]
97# @param Arch:  The Arch of item of section [Defines]
98#
99# @retval RecordSet: A list of all matched records
100#
101def QueryDefinesItem(Table, Name, Arch, BelongsToFile):
102    SqlCommand = """select Value2 from %s
103                    where Model = %s
104                    and Value1 = '%s'
105                    and Arch = '%s'
106                    and BelongsToFile = %s
107                    and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(Arch), BelongsToFile)
108    RecordSet = Table.Exec(SqlCommand)
109    if len(RecordSet) < 1:
110        SqlCommand = """select Value2 from %s
111                    where Model = %s
112                    and Value1 = '%s'
113                    and Arch = '%s'
114                    and BelongsToFile = %s
115                    and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(TAB_ARCH_COMMON.upper()), BelongsToFile)
116        RecordSet = Table.Exec(SqlCommand)
117    if len(RecordSet) == 1:
118        if Name == TAB_INF_DEFINES_LIBRARY_CLASS:
119            return [RecordSet[0][0]]
120        else:
121            return GetSplitValueList(RecordSet[0][0])
122    elif len(RecordSet) < 1:
123        return ['']
124    elif len(RecordSet) > 1:
125        RetVal = []
126        for Record in RecordSet:
127            if Name == TAB_INF_DEFINES_LIBRARY_CLASS:
128                RetVal.append(Record[0])
129            else:
130                Items = GetSplitValueList(Record[0])
131                for Item in Items:
132                    RetVal.append(Item)
133        return RetVal
134
135##QueryDefinesItem
136#
137# Search item of section [Defines] by name, return its values
138#
139# @param Table: The Table to be executed
140# @param Name:  The Name of item of section [Defines]
141# @param Arch:  The Arch of item of section [Defines]
142#
143# @retval RecordSet: A list of all matched records
144#
145def QueryDefinesItem2(Table, Arch, BelongsToFile):
146    SqlCommand = """select Value1, Value2, StartLine from %s
147                    where Model = %s
148                    and Arch = '%s'
149                    and BelongsToFile = %s
150                    and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Arch), BelongsToFile)
151    RecordSet = Table.Exec(SqlCommand)
152    if len(RecordSet) < 1:
153        SqlCommand = """select Value1, Value2, StartLine from %s
154                    where Model = %s
155                    and Arch = '%s'
156                    and BelongsToFile = %s
157                    and Enabled > -1""" % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(TAB_ARCH_COMMON), BelongsToFile)
158        RecordSet = Table.Exec(SqlCommand)
159
160    return RecordSet
161
162##QueryDscItem
163#
164# Search all dsc item for a specific section
165#
166# @param Table: The Table to be executed
167# @param Model:  The type of section
168#
169# @retval RecordSet: A list of all matched records
170#
171def QueryDscItem(Table, Model, BelongsToItem, BelongsToFile):
172    SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s
173                    where Model = %s
174                    and BelongsToItem = %s
175                    and BelongsToFile = %s
176                    and Enabled > -1""" % (Table.Table, Model, BelongsToItem, BelongsToFile)
177    return Table.Exec(SqlCommand)
178
179##QueryDecItem
180#
181# Search all dec item for a specific section
182#
183# @param Table: The Table to be executed
184# @param Model:  The type of section
185#
186# @retval RecordSet: A list of all matched records
187#
188def QueryDecItem(Table, Model, BelongsToItem):
189    SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s
190                    where Model = %s
191                    and BelongsToItem = %s
192                    and Enabled > -1""" % (Table.Table, Model, BelongsToItem)
193    return Table.Exec(SqlCommand)
194
195##QueryInfItem
196#
197# Search all dec item for a specific section
198#
199# @param Table: The Table to be executed
200# @param Model: The type of section
201#
202# @retval RecordSet: A list of all matched records
203#
204def QueryInfItem(Table, Model, BelongsToItem):
205    SqlCommand = """select Value1, Arch, StartLine, ID, Value2 from %s
206                    where Model = %s
207                    and BelongsToItem = %s
208                    and Enabled > -1""" % (Table.Table, Model, BelongsToItem)
209    return Table.Exec(SqlCommand)
210
211## GetBuildOption
212#
213# Parse a string with format "[<Family>:]<ToolFlag>=Flag"
214# Return (Family, ToolFlag, Flag)
215#
216# @param String:  String with BuildOption statement
217# @param File:    The file which defines build option, used in error report
218#
219# @retval truple() A truple structure as (Family, ToolChain, Flag)
220#
221def GetBuildOption(String, File, LineNo = -1):
222    (Family, ToolChain, Flag) = ('', '', '')
223    if String.find(TAB_EQUAL_SPLIT) < 0:
224        RaiseParserError(String, 'BuildOptions', File, '[<Family>:]<ToolFlag>=Flag', LineNo)
225    else:
226        List = GetSplitValueList(String, TAB_EQUAL_SPLIT, MaxSplit = 1)
227        if List[0].find(':') > -1:
228            Family = List[0][ : List[0].find(':')].strip()
229            ToolChain = List[0][List[0].find(':') + 1 : ].strip()
230        else:
231            ToolChain = List[0].strip()
232        Flag = List[1].strip()
233    return (Family, ToolChain, Flag)
234
235## Get Library Class
236#
237# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
238#
239# @param Item:           String as <LibraryClassKeyWord>|<LibraryInstance>
240# @param ContainerFile:  The file which describes the library class, used for error report
241#
242# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item
243#
244def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo = -1):
245    List = GetSplitValueList(Item[0])
246    SupMod = SUP_MODULE_LIST_STRING
247    if len(List) != 2:
248        RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, '<LibraryClassKeyWord>|<LibraryInstance>')
249    else:
250        CheckFileType(List[1], '.Inf', ContainerFile, 'library class instance', Item[0], LineNo)
251        CheckFileExist(WorkspaceDir, List[1], ContainerFile, 'LibraryClasses', Item[0], LineNo)
252        if Item[1] != '':
253            SupMod = Item[1]
254
255    return (List[0], List[1], SupMod)
256
257## Get Library Class
258#
259# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>][|<TokenSpaceGuidCName>.<PcdCName>]
260#
261# @param Item:           String as <LibraryClassKeyWord>|<LibraryInstance>
262# @param ContainerFile:  The file which describes the library class, used for error report
263#
264# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item
265#
266def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo = -1):
267    ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2))
268    SupMod = SUP_MODULE_LIST_STRING
269
270    if len(ItemList) > 5:
271        RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, '<LibraryClassKeyWord>[|<LibraryInstance>][|<TokenSpaceGuidCName>.<PcdCName>]')
272    else:
273        CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', Item[0], LineNo)
274        CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, 'LibraryClasses', Item[0], LineNo)
275        if ItemList[2] != '':
276            CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', ContainerFile, LineNo)
277        if Item[1] != '':
278            SupMod = Item[1]
279
280    return (ItemList[0], ItemList[1], ItemList[2], SupMod)
281
282## CheckPcdTokenInfo
283#
284# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>
285#
286# @param TokenInfoString:  String to be checked
287# @param Section:          Used for error report
288# @param File:             Used for error report
289#
290# @retval True PcdTokenInfo is in correct format
291#
292def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo = -1):
293    Format = '<TokenSpaceGuidCName>.<PcdCName>'
294    if TokenInfoString != '' and TokenInfoString is not None:
295        TokenInfoList = GetSplitValueList(TokenInfoString, TAB_SPLIT)
296        if len(TokenInfoList) == 2:
297            return True
298
299    RaiseParserError(TokenInfoString, Section, File, Format, LineNo)
300
301## Get Pcd
302#
303# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]
304#
305# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]
306# @param ContainerFile:  The file which describes the pcd, used for error report
307#
308# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type)
309#
310def GetPcd(Item, Type, ContainerFile, LineNo = -1):
311    TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', ''
312    List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2)
313
314    if len(List) < 4 or len(List) > 6:
315        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]', LineNo)
316    else:
317        Value = List[1]
318        MaximumDatumSize = List[2]
319        Token = List[3]
320
321    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
322        (TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT)
323
324    return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type)
325
326## Get FeatureFlagPcd
327#
328# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
329#
330# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
331# @param ContainerFile:  The file which describes the pcd, used for error report
332#
333# @retval (TokenInfo[1], TokenInfo[0], List[1], Type)
334#
335def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo = -1):
336    TokenGuid, TokenName, Value = '', '', ''
337    List = GetSplitValueList(Item)
338    if len(List) != 2:
339        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', LineNo)
340    else:
341        Value = List[1]
342    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
343        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
344
345    return (TokenName, TokenGuid, Value, Type)
346
347## Get DynamicDefaultPcd
348#
349# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]]
350#
351# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
352# @param ContainerFile:  The file which describes the pcd, used for error report
353#
354# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type)
355#
356def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo = -1):
357    TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', ''
358    List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2)
359    if len(List) < 4 or len(List) > 8:
360        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]]', LineNo)
361    else:
362        Value = List[1]
363        DatumTyp = List[2]
364        MaxDatumSize = List[3]
365    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
366        (TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT)
367
368    return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type)
369
370## Get DynamicHiiPcd
371#
372# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
373#
374# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
375# @param ContainerFile:  The file which describes the pcd, used for error report
376#
377# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], List[4], List[5], Type)
378#
379def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo = -1):
380    TokenGuid, TokenName, L1, L2, L3, L4, L5 = '', '', '', '', '', '', ''
381    List = GetSplitValueList(Item + TAB_VALUE_SPLIT * 2)
382    if len(List) < 6 or len(List) > 8:
383        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]', LineNo)
384    else:
385        L1, L2, L3, L4, L5 = List[1], List[2], List[3], List[4], List[5]
386    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
387        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
388
389    return (TokenName, TokenGuid, L1, L2, L3, L4, L5, Type)
390
391## Get DynamicVpdPcd
392#
393# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>]
394#
395# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
396# @param ContainerFile:  The file which describes the pcd, used for error report
397#
398# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], Type)
399#
400def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo = -1):
401    TokenGuid, TokenName, L1, L2 = '', '', '', ''
402    List = GetSplitValueList(Item + TAB_VALUE_SPLIT)
403    if len(List) < 3 or len(List) > 4:
404        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, '<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>]', LineNo)
405    else:
406        L1, L2 = List[1], List[2]
407    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
408        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
409
410    return (TokenName, TokenGuid, L1, L2, Type)
411
412## GetComponent
413#
414# Parse block of the components defined in dsc file
415# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
416#
417# @param Lines:             The content to be parsed
418# @param KeyValues:         To store data after parsing
419#
420# @retval True Get component successfully
421#
422def GetComponent(Lines, KeyValues):
423    (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
424    ListItem = None
425    LibraryClassItem = []
426    BuildOption = []
427    Pcd = []
428
429    for Line in Lines:
430        Line = Line[0]
431
432        #
433        # Ignore !include statement
434        #
435        if Line.upper().find(TAB_INCLUDE.upper() + ' ') > -1 or Line.upper().find(TAB_DEFINE + ' ') > -1:
436            continue
437
438        if findBlock == False:
439            ListItem = Line
440            #
441            # find '{' at line tail
442            #
443            if Line.endswith('{'):
444                findBlock = True
445                ListItem = CleanString(Line.rsplit('{', 1)[0], DataType.TAB_COMMENT_SPLIT)
446
447        #
448        # Parse a block content
449        #
450        if findBlock:
451            if Line.find('<LibraryClasses>') != -1:
452                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False)
453                continue
454            if Line.find('<BuildOptions>') != -1:
455                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False)
456                continue
457            if Line.find('<PcdsFeatureFlag>') != -1:
458                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False)
459                continue
460            if Line.find('<PcdsPatchableInModule>') != -1:
461                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False)
462                continue
463            if Line.find('<PcdsFixedAtBuild>') != -1:
464                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False)
465                continue
466            if Line.find('<PcdsDynamic>') != -1:
467                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False)
468                continue
469            if Line.find('<PcdsDynamicEx>') != -1:
470                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True)
471                continue
472            if Line.endswith('}'):
473                #
474                # find '}' at line tail
475                #
476                KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd])
477                (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
478                LibraryClassItem, BuildOption, Pcd = [], [], []
479                continue
480
481        if findBlock:
482            if findLibraryClass:
483                LibraryClassItem.append(Line)
484            elif findBuildOption:
485                BuildOption.append(Line)
486            elif findPcdsFeatureFlag:
487                Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line))
488            elif findPcdsPatchableInModule:
489                Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line))
490            elif findPcdsFixedAtBuild:
491                Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line))
492            elif findPcdsDynamic:
493                Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line))
494            elif findPcdsDynamicEx:
495                Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line))
496        else:
497            KeyValues.append([ListItem, [], [], []])
498
499    return True
500
501## GetExec
502#
503# Parse a string with format "InfFilename [EXEC = ExecFilename]"
504# Return (InfFilename, ExecFilename)
505#
506# @param String:  String with EXEC statement
507#
508# @retval truple() A pair as (InfFilename, ExecFilename)
509#
510def GetExec(String):
511    InfFilename = ''
512    ExecFilename = ''
513    if String.find('EXEC') > -1:
514        InfFilename = String[ : String.find('EXEC')].strip()
515        ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip()
516    else:
517        InfFilename = String.strip()
518
519    return (InfFilename, ExecFilename)
520
521## GetComponents
522#
523# Parse block of the components defined in dsc file
524# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
525#
526# @param Lines:             The content to be parsed
527# @param Key:               Reserved
528# @param KeyValues:         To store data after parsing
529# @param CommentCharacter:  Comment char, used to ignore comment content
530#
531# @retval True Get component successfully
532#
533def GetComponents(Lines, Key, KeyValues, CommentCharacter):
534    if Lines.find(DataType.TAB_SECTION_END) > -1:
535        Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
536    (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
537    ListItem = None
538    LibraryClassItem = []
539    BuildOption = []
540    Pcd = []
541
542    LineList = Lines.split('\n')
543    for Line in LineList:
544        Line = CleanString(Line, CommentCharacter)
545        if Line is None or Line == '':
546            continue
547
548        if findBlock == False:
549            ListItem = Line
550            #
551            # find '{' at line tail
552            #
553            if Line.endswith('{'):
554                findBlock = True
555                ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter)
556
557        #
558        # Parse a block content
559        #
560        if findBlock:
561            if Line.find('<LibraryClasses>') != -1:
562                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (True, False, False, False, False, False, False)
563                continue
564            if Line.find('<BuildOptions>') != -1:
565                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, True, False, False, False, False, False)
566                continue
567            if Line.find('<PcdsFeatureFlag>') != -1:
568                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, True, False, False, False, False)
569                continue
570            if Line.find('<PcdsPatchableInModule>') != -1:
571                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, True, False, False, False)
572                continue
573            if Line.find('<PcdsFixedAtBuild>') != -1:
574                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, True, False, False)
575                continue
576            if Line.find('<PcdsDynamic>') != -1:
577                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, True, False)
578                continue
579            if Line.find('<PcdsDynamicEx>') != -1:
580                (findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, True)
581                continue
582            if Line.endswith('}'):
583                #
584                # find '}' at line tail
585                #
586                KeyValues.append([ListItem, LibraryClassItem, BuildOption, Pcd])
587                (findBlock, findLibraryClass, findBuildOption, findPcdsFeatureFlag, findPcdsPatchableInModule, findPcdsFixedAtBuild, findPcdsDynamic, findPcdsDynamicEx) = (False, False, False, False, False, False, False, False)
588                LibraryClassItem, BuildOption, Pcd = [], [], []
589                continue
590
591        if findBlock:
592            if findLibraryClass:
593                LibraryClassItem.append(Line)
594            elif findBuildOption:
595                BuildOption.append(Line)
596            elif findPcdsFeatureFlag:
597                Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line))
598            elif findPcdsPatchableInModule:
599                Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line))
600            elif findPcdsFixedAtBuild:
601                Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line))
602            elif findPcdsDynamic:
603                Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line))
604            elif findPcdsDynamicEx:
605                Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line))
606        else:
607            KeyValues.append([ListItem, [], [], []])
608
609    return True
610
611## Get Source
612#
613# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
614#
615# @param Item:           String as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
616# @param ContainerFile:  The file which describes the library class, used for error report
617#
618# @retval (List[0], List[1], List[2], List[3], List[4])
619#
620def GetSource(Item, ContainerFile, FileRelativePath, LineNo = -1):
621    ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4
622    List = GetSplitValueList(ItemNew)
623    if len(List) < 5 or len(List) > 9:
624        RaiseParserError(Item, 'Sources', ContainerFile, '<Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]', LineNo)
625    List[0] = NormPath(List[0])
626    CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', Item, LineNo)
627    if List[4] != '':
628        CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo)
629
630    return (List[0], List[1], List[2], List[3], List[4])
631
632## Get Binary
633#
634# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
635#
636# @param Item:           String as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
637# @param ContainerFile:  The file which describes the library class, used for error report
638#
639# @retval (List[0], List[1], List[2], List[3])
640# @retval List
641#
642def GetBinary(Item, ContainerFile, FileRelativePath, LineNo = -1):
643    ItemNew = Item + DataType.TAB_VALUE_SPLIT
644    List = GetSplitValueList(ItemNew)
645    if len(List) != 4 and len(List) != 5:
646        RaiseParserError(Item, 'Binaries', ContainerFile, "<FileType>|<Filename>|<Target>[|<TokenSpaceGuidCName>.<PcdCName>]", LineNo)
647    else:
648        if List[3] != '':
649            CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo)
650
651    if len(List) == 4:
652        return (List[0], List[1], List[2], List[3])
653    elif len(List) == 3:
654        return (List[0], List[1], List[2], '')
655    elif len(List) == 2:
656        return (List[0], List[1], '', '')
657    elif len(List) == 1:
658        return (List[0], '', '', '')
659
660## Get Guids/Protocols/Ppis
661#
662# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
663#
664# @param Item:           String as <GuidCName>[|<PcdFeatureFlag>]
665# @param Type:           Type of parsing string
666# @param ContainerFile:  The file which describes the library class, used for error report
667#
668# @retval (List[0], List[1])
669#
670def GetGuidsProtocolsPpisOfInf(Item, Type, ContainerFile, LineNo = -1):
671    ItemNew = Item + TAB_VALUE_SPLIT
672    List = GetSplitValueList(ItemNew)
673    if List[1] != '':
674        CheckPcdTokenInfo(List[1], Type, ContainerFile, LineNo)
675
676    return (List[0], List[1])
677
678## Get Guids/Protocols/Ppis
679#
680# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
681#
682# @param Item:           String as <GuidCName>=<GuidValue>
683# @param Type:           Type of parsing string
684# @param ContainerFile:  The file which describes the library class, used for error report
685#
686# @retval (List[0], List[1])
687#
688def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo = -1):
689    List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT)
690    if len(List) != 2:
691        RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', LineNo)
692
693    return (List[0], List[1])
694
695## GetPackage
696#
697# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
698#
699# @param Item:           String as <PackagePath>[|<PcdFeatureFlag>]
700# @param Type:           Type of parsing string
701# @param ContainerFile:  The file which describes the library class, used for error report
702#
703# @retval (List[0], List[1])
704#
705def GetPackage(Item, ContainerFile, FileRelativePath, LineNo = -1):
706    ItemNew = Item + TAB_VALUE_SPLIT
707    List = GetSplitValueList(ItemNew)
708    CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo)
709    CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', List[0], LineNo)
710
711    if List[1] != '':
712        CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo)
713
714    return (List[0], List[1])
715
716## Get Pcd Values of Inf
717#
718# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>]
719#
720# @param Item:  The string describes pcd
721# @param Type:  The type of Pcd
722# @param File:  The file which describes the pcd, used for error report
723#
724# @retval (TokenSpcCName, TokenCName, Value, ItemType) Formatted Pcd Item
725#
726def GetPcdOfInf(Item, Type, File, LineNo):
727    Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]'
728    TokenGuid, TokenName, Value, InfType = '', '', '', ''
729
730    if Type == TAB_PCDS_FIXED_AT_BUILD:
731        InfType = TAB_INF_FIXED_PCD
732    elif Type == TAB_PCDS_PATCHABLE_IN_MODULE:
733        InfType = TAB_INF_PATCH_PCD
734    elif Type == TAB_PCDS_FEATURE_FLAG:
735        InfType = TAB_INF_FEATURE_PCD
736    elif Type == TAB_PCDS_DYNAMIC_EX:
737        InfType = TAB_INF_PCD_EX
738    elif Type == TAB_PCDS_DYNAMIC:
739        InfType = TAB_INF_PCD
740    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT)
741    if len(List) < 2 or len(List) > 3:
742        RaiseParserError(Item, InfType, File, Format, LineNo)
743    else:
744        Value = List[1]
745    TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
746    if len(TokenInfo) != 2:
747        RaiseParserError(Item, InfType, File, Format, LineNo)
748    else:
749        TokenGuid = TokenInfo[0]
750        TokenName = TokenInfo[1]
751
752    return (TokenGuid, TokenName, Value, Type)
753
754
755## Get Pcd Values of Dec
756#
757# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>
758# @retval (TokenSpcCName, TokenCName, Value, DatumType, Token, ItemType) Formatted Pcd Item
759#
760def GetPcdOfDec(Item, Type, File, LineNo = -1):
761    Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>'
762    TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', ''
763    List = GetSplitValueList(Item)
764    if len(List) != 4:
765        RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
766    else:
767        Value = List[1]
768        DatumType = List[2]
769        Token = List[3]
770    TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
771    if len(TokenInfo) != 2:
772        RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
773    else:
774        TokenGuid = TokenInfo[0]
775        TokenName = TokenInfo[1]
776
777    return (TokenGuid, TokenName, Value, DatumType, Token, Type)
778
779## Parse DEFINE statement
780#
781# Get DEFINE macros
782#
783# 1. Insert a record into TblDec
784# Value1: Macro Name
785# Value2: Macro Value
786#
787def ParseDefine(LineValue, StartLine, Table, FileID, Filename, SectionName, SectionModel, Arch):
788    EdkLogger.debug(EdkLogger.DEBUG_2, "DEFINE statement '%s' found in section %s" % (LineValue, SectionName))
789    Define = GetSplitValueList(CleanString(LineValue[LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') + len(DataType.TAB_DEFINE + ' ') : ]), TAB_EQUAL_SPLIT, 1)
790    Table.Insert(MODEL_META_DATA_DEFINE, Define[0], Define[1], '', '', '', Arch, SectionModel, FileID, StartLine, -1, StartLine, -1, 0)
791
792## InsertSectionItems
793#
794# Insert item data of a section to a dict
795#
796def InsertSectionItems(Model, CurrentSection, SectionItemList, ArchList, ThirdList, RecordSet):
797    # Insert each item data of a section
798    for Index in range(0, len(ArchList)):
799        Arch = ArchList[Index]
800        Third = ThirdList[Index]
801        if Arch == '':
802            Arch = TAB_ARCH_COMMON
803
804        Records = RecordSet[Model]
805        for SectionItem in SectionItemList:
806            BelongsToItem, EndLine, EndColumn = -1, -1, -1
807            LineValue, StartLine, EndLine, Comment = SectionItem[0], SectionItem[1], SectionItem[1], SectionItem[2]
808
809            EdkLogger.debug(4, "Parsing %s ..." %LineValue)
810            # And then parse DEFINE statement
811            if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
812                continue
813
814            # At last parse other sections
815            ID = -1
816            Records.append([LineValue, Arch, StartLine, ID, Third, Comment])
817
818        if RecordSet != {}:
819            RecordSet[Model] = Records
820
821## Insert records to database
822#
823# Insert item data of a section to database
824# @param Table:            The Table to be inserted
825# @param FileID:           The ID of belonging file
826# @param Filename:         The name of belonging file
827# @param CurrentSection:   The name of current section
828# @param SectionItemList:  A list of items of the section
829# @param ArchList:         A list of arches
830# @param ThirdList:        A list of third parameters, ModuleType for LibraryClass and SkuId for Dynamic Pcds
831# @param IfDefList:        A list of all conditional statements
832# @param RecordSet:        A dict of all parsed records
833#
834def InsertSectionItemsIntoDatabase(Table, FileID, Filename, Model, CurrentSection, SectionItemList, ArchList, ThirdList, IfDefList, RecordSet):
835    #
836    # Insert each item data of a section
837    #
838    for Index in range(0, len(ArchList)):
839        Arch = ArchList[Index]
840        Third = ThirdList[Index]
841        if Arch == '':
842            Arch = TAB_ARCH_COMMON
843
844        Records = RecordSet[Model]
845        for SectionItem in SectionItemList:
846            BelongsToItem, EndLine, EndColumn = -1, -1, -1
847            LineValue, StartLine, EndLine = SectionItem[0], SectionItem[1], SectionItem[1]
848
849            EdkLogger.debug(4, "Parsing %s ..." %LineValue)
850            #
851            # And then parse DEFINE statement
852            #
853            if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
854                ParseDefine(LineValue, StartLine, Table, FileID, Filename, CurrentSection, Model, Arch)
855                continue
856
857            #
858            # At last parse other sections
859            #
860            ID = Table.Insert(Model, LineValue, Third, Third, '', '', Arch, -1, FileID, StartLine, -1, StartLine, -1, 0)
861            Records.append([LineValue, Arch, StartLine, ID, Third])
862
863        if RecordSet != {}:
864            RecordSet[Model] = Records
865
866## GenMetaDatSectionItem
867def GenMetaDatSectionItem(Key, Value, List):
868    if Key not in List:
869        List[Key] = [Value]
870    else:
871        List[Key].append(Value)
872
873## IsValidWord
874#
875# Check whether the word is valid.
876# <Word>   ::=  (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with
877#               optional
878#               dash "-" and/or underscore "_" characters. No whitespace
879#               characters are permitted.
880#
881# @param Word:  The word string need to be checked.
882#
883def IsValidWord(Word):
884    if not Word:
885        return False
886    #
887    # The first char should be alpha, _ or Digit.
888    #
889    if not Word[0].isalnum() and \
890       not Word[0] == '_' and \
891       not Word[0].isdigit():
892        return False
893
894    LastChar = ''
895    for Char in Word[1:]:
896        if (not Char.isalpha()) and \
897           (not Char.isdigit()) and \
898           Char != '-' and \
899           Char != '_' and \
900           Char != '.':
901            return False
902        if Char == '.' and LastChar == '.':
903            return False
904        LastChar = Char
905
906    return True
907