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