1## @file
2# This file is used to define common parsing related functions used in parsing
3# INF/DEC/DSC process
4#
5# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6#
7# SPDX-License-Identifier: BSD-2-Clause-Patent
8#
9
10'''
11Parsing
12'''
13from __future__ import absolute_import
14
15##
16# Import Modules
17#
18import os.path
19import re
20
21from Library.StringUtils import RaiseParserError
22from Library.StringUtils import GetSplitValueList
23from Library.StringUtils import CheckFileType
24from Library.StringUtils import CheckFileExist
25from Library.StringUtils import CleanString
26from Library.StringUtils import NormPath
27
28from Logger.ToolError import FILE_NOT_FOUND
29from Logger.ToolError import FatalError
30from Logger.ToolError import FORMAT_INVALID
31
32from Library import DataType
33
34from Library.Misc import GuidStructureStringToGuidString
35from Library.Misc import CheckGuidRegFormat
36from Logger import StringTable as ST
37import Logger.Log as Logger
38
39from Parser.DecParser import Dec
40from . import GlobalData
41
42gPKG_INFO_DICT = {}
43
44## GetBuildOption
45#
46# Parse a string with format "[<Family>:]<ToolFlag>=Flag"
47# Return (Family, ToolFlag, Flag)
48#
49# @param String:  String with BuildOption statement
50# @param File:    The file which defines build option, used in error report
51#
52def GetBuildOption(String, File, LineNo= -1):
53    (Family, ToolChain, Flag) = ('', '', '')
54    if String.find(DataType.TAB_EQUAL_SPLIT) < 0:
55        RaiseParserError(String, 'BuildOptions', File, \
56                         '[<Family>:]<ToolFlag>=Flag', LineNo)
57    else:
58        List = GetSplitValueList(String, DataType.TAB_EQUAL_SPLIT, MaxSplit=1)
59        if List[0].find(':') > -1:
60            Family = List[0][ : List[0].find(':')].strip()
61            ToolChain = List[0][List[0].find(':') + 1 : ].strip()
62        else:
63            ToolChain = List[0].strip()
64        Flag = List[1].strip()
65    return (Family, ToolChain, Flag)
66
67## Get Library Class
68#
69# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
70#
71# @param Item:           String as <LibraryClassKeyWord>|<LibraryInstance>
72# @param ContainerFile:  The file which describes the library class, used for
73#                        error report
74#
75def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo= -1):
76    List = GetSplitValueList(Item[0])
77    SupMod = DataType.SUP_MODULE_LIST_STRING
78    if len(List) != 2:
79        RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, \
80                         '<LibraryClassKeyWord>|<LibraryInstance>')
81    else:
82        CheckFileType(List[1], '.Inf', ContainerFile, \
83                      'library class instance', Item[0], LineNo)
84        CheckFileExist(WorkspaceDir, List[1], ContainerFile, \
85                       'LibraryClasses', Item[0], LineNo)
86        if Item[1] != '':
87            SupMod = Item[1]
88
89    return (List[0], List[1], SupMod)
90
91## Get Library Class
92#
93# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>]
94# [|<TokenSpaceGuidCName>.<PcdCName>]
95#
96# @param Item:           String as <LibraryClassKeyWord>|<LibraryInstance>
97# @param ContainerFile:  The file which describes the library class, used for
98#                        error report
99#
100def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo= -1):
101    ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2))
102    SupMod = DataType.SUP_MODULE_LIST_STRING
103
104    if len(ItemList) > 5:
105        RaiseParserError\
106        (Item[0], 'LibraryClasses', ContainerFile, \
107         '<LibraryClassKeyWord>[|<LibraryInstance>]\
108         [|<TokenSpaceGuidCName>.<PcdCName>]')
109    else:
110        CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', \
111                      Item[0], LineNo)
112        CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, \
113                       'LibraryClasses', Item[0], LineNo)
114        if ItemList[2] != '':
115            CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', \
116                              ContainerFile, LineNo)
117        if Item[1] != '':
118            SupMod = Item[1]
119
120    return (ItemList[0], ItemList[1], ItemList[2], SupMod)
121
122## CheckPcdTokenInfo
123#
124# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>
125#
126# @param TokenInfoString:  String to be checked
127# @param Section:          Used for error report
128# @param File:             Used for error report
129#
130def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo= -1):
131    Format = '<TokenSpaceGuidCName>.<PcdCName>'
132    if TokenInfoString != '' and TokenInfoString is not None:
133        TokenInfoList = GetSplitValueList(TokenInfoString, DataType.TAB_SPLIT)
134        if len(TokenInfoList) == 2:
135            return True
136
137    RaiseParserError(TokenInfoString, Section, File, Format, LineNo)
138
139## Get Pcd
140#
141# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>
142# [|<Type>|<MaximumDatumSize>]
143#
144# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|
145#                        <Value>[|<Type>|<MaximumDatumSize>]
146# @param ContainerFile:  The file which describes the pcd, used for error
147#                        report
148
149#
150def GetPcd(Item, Type, ContainerFile, LineNo= -1):
151    TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', ''
152    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
153
154    if len(List) < 4 or len(List) > 6:
155        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
156                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\
157                         [|<Type>|<MaximumDatumSize>]', LineNo)
158    else:
159        Value = List[1]
160        MaximumDatumSize = List[2]
161        Token = List[3]
162
163    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
164        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
165
166    return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type)
167
168## Get FeatureFlagPcd
169#
170# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
171#
172# @param Item:           String as <PcdTokenSpaceGuidCName>
173#                        .<TokenCName>|TRUE/FALSE
174# @param ContainerFile:  The file which describes the pcd, used for error
175#                        report
176#
177def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo= -1):
178    TokenGuid, TokenName, Value = '', '', ''
179    List = GetSplitValueList(Item)
180    if len(List) != 2:
181        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
182                         '<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', \
183                         LineNo)
184    else:
185        Value = List[1]
186    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
187        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
188
189    return (TokenName, TokenGuid, Value, Type)
190
191## Get DynamicDefaultPcd
192#
193# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>
194# |<Value>[|<DatumTyp>[|<MaxDatumSize>]]
195#
196# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|
197#                        TRUE/FALSE
198# @param ContainerFile:  The file which describes the pcd, used for error
199#                        report
200#
201def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo= -1):
202    TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', ''
203    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
204    if len(List) < 4 or len(List) > 8:
205        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
206                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\
207                         [|<DatumTyp>[|<MaxDatumSize>]]', LineNo)
208    else:
209        Value = List[1]
210        DatumTyp = List[2]
211        MaxDatumSize = List[3]
212    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
213        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
214
215    return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type)
216
217## Get DynamicHiiPcd
218#
219# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|
220# <VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
221#
222# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|
223#                        TRUE/FALSE
224# @param ContainerFile:  The file which describes the pcd, used for error
225#                        report
226#
227def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo= -1):
228    TokenGuid, TokenName, List1, List2, List3, List4, List5 = \
229    '', '', '', '', '', '', ''
230    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
231    if len(List) < 6 or len(List) > 8:
232        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
233                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|\
234                         <VariableGuidCName>|<VariableOffset>[|<DefaultValue>\
235                         [|<MaximumDatumSize>]]', LineNo)
236    else:
237        List1, List2, List3, List4, List5 = \
238        List[1], List[2], List[3], List[4], List[5]
239    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
240        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
241
242    return (TokenName, TokenGuid, List1, List2, List3, List4, List5, Type)
243
244## Get DynamicVpdPcd
245#
246# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|
247# <VpdOffset>[|<MaximumDatumSize>]
248#
249# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>
250#                        |TRUE/FALSE
251# @param ContainerFile:  The file which describes the pcd, used for error
252#                        report
253#
254def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo= -1):
255    TokenGuid, TokenName, List1, List2 = '', '', '', ''
256    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT)
257    if len(List) < 3 or len(List) > 4:
258        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
259                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>\
260                         [|<MaximumDatumSize>]', LineNo)
261    else:
262        List1, List2 = List[1], List[2]
263    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
264        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
265
266    return (TokenName, TokenGuid, List1, List2, Type)
267
268## GetComponent
269#
270# Parse block of the components defined in dsc file
271# Set KeyValues as [ ['component name', [lib1, lib2, lib3],
272# [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
273#
274# @param Lines:             The content to be parsed
275# @param KeyValues:         To store data after parsing
276#
277def GetComponent(Lines, KeyValues):
278    (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
279     FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \
280     FindPcdsDynamicEx) = (False, False, False, False, False, False, False, \
281                           False)
282    ListItem = None
283    LibraryClassItem = []
284    BuildOption = []
285    Pcd = []
286
287    for Line in Lines:
288        Line = Line[0]
289        #
290        # Ignore !include statement
291        #
292        if Line.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1 or \
293        Line.upper().find(DataType.TAB_DEFINE + ' ') > -1:
294            continue
295
296        if FindBlock == False:
297            ListItem = Line
298            #
299            # find '{' at line tail
300            #
301            if Line.endswith('{'):
302                FindBlock = True
303                ListItem = CleanString(Line.rsplit('{', 1)[0], \
304                                       DataType.TAB_COMMENT_SPLIT)
305
306        #
307        # Parse a block content
308        #
309        if FindBlock:
310            if Line.find('<LibraryClasses>') != -1:
311                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
312                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
313                 FindPcdsDynamic, FindPcdsDynamicEx) = \
314                 (True, False, False, False, False, False, False)
315                continue
316            if Line.find('<BuildOptions>') != -1:
317                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
318                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
319                 FindPcdsDynamic, FindPcdsDynamicEx) = \
320                 (False, True, False, False, False, False, False)
321                continue
322            if Line.find('<PcdsFeatureFlag>') != -1:
323                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
324                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
325                 FindPcdsDynamic, FindPcdsDynamicEx) = \
326                 (False, False, True, False, False, False, False)
327                continue
328            if Line.find('<PcdsPatchableInModule>') != -1:
329                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
330                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
331                 FindPcdsDynamic, FindPcdsDynamicEx) = \
332                 (False, False, False, True, False, False, False)
333                continue
334            if Line.find('<PcdsFixedAtBuild>') != -1:
335                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
336                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
337                 FindPcdsDynamic, FindPcdsDynamicEx) = \
338                 (False, False, False, False, True, False, False)
339                continue
340            if Line.find('<PcdsDynamic>') != -1:
341                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
342                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
343                 FindPcdsDynamic, FindPcdsDynamicEx) = \
344                 (False, False, False, False, False, True, False)
345                continue
346            if Line.find('<PcdsDynamicEx>') != -1:
347                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
348                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
349                 FindPcdsDynamic, FindPcdsDynamicEx) = \
350                 (False, False, False, False, False, False, True)
351                continue
352            if Line.endswith('}'):
353                #
354                # find '}' at line tail
355                #
356                KeyValues.append([ListItem, LibraryClassItem, \
357                                  BuildOption, Pcd])
358                (FindBlock, FindLibraryClass, FindBuildOption, \
359                 FindPcdsFeatureFlag, FindPcdsPatchableInModule, \
360                 FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \
361                 (False, False, False, False, False, False, False, False)
362                LibraryClassItem, BuildOption, Pcd = [], [], []
363                continue
364
365        if FindBlock:
366            if FindLibraryClass:
367                LibraryClassItem.append(Line)
368            elif FindBuildOption:
369                BuildOption.append(Line)
370            elif FindPcdsFeatureFlag:
371                Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line))
372            elif FindPcdsPatchableInModule:
373                Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line))
374            elif FindPcdsFixedAtBuild:
375                Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line))
376            elif FindPcdsDynamic:
377                Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line))
378            elif FindPcdsDynamicEx:
379                Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line))
380        else:
381            KeyValues.append([ListItem, [], [], []])
382
383    return True
384
385## GetExec
386#
387# Parse a string with format "InfFilename [EXEC = ExecFilename]"
388# Return (InfFilename, ExecFilename)
389#
390# @param String:  String with EXEC statement
391#
392def GetExec(String):
393    InfFilename = ''
394    ExecFilename = ''
395    if String.find('EXEC') > -1:
396        InfFilename = String[ : String.find('EXEC')].strip()
397        ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip()
398    else:
399        InfFilename = String.strip()
400
401    return (InfFilename, ExecFilename)
402
403## GetComponents
404#
405# Parse block of the components defined in dsc file
406# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3],
407# [pcd1, pcd2, pcd3]], ...]
408#
409# @param Lines:             The content to be parsed
410# @param Key:               Reserved
411# @param KeyValues:         To store data after parsing
412# @param CommentCharacter:  Comment char, used to ignore comment content
413#
414# @retval True Get component successfully
415#
416def GetComponents(Lines, KeyValues, CommentCharacter):
417    if Lines.find(DataType.TAB_SECTION_END) > -1:
418        Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
419    (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
420     FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \
421     FindPcdsDynamicEx) = \
422     (False, False, False, False, False, False, False, False)
423    ListItem = None
424    LibraryClassItem = []
425    BuildOption = []
426    Pcd = []
427
428    LineList = Lines.split('\n')
429    for Line in LineList:
430        Line = CleanString(Line, CommentCharacter)
431        if Line is None or Line == '':
432            continue
433
434        if FindBlock == False:
435            ListItem = Line
436            #
437            # find '{' at line tail
438            #
439            if Line.endswith('{'):
440                FindBlock = True
441                ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter)
442
443        #
444        # Parse a block content
445        #
446        if FindBlock:
447            if Line.find('<LibraryClasses>') != -1:
448                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
449                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
450                 FindPcdsDynamic, FindPcdsDynamicEx) = \
451                 (True, False, False, False, False, False, False)
452                continue
453            if Line.find('<BuildOptions>') != -1:
454                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
455                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
456                 FindPcdsDynamic, FindPcdsDynamicEx) = \
457                 (False, True, False, False, False, False, False)
458                continue
459            if Line.find('<PcdsFeatureFlag>') != -1:
460                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
461                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
462                 FindPcdsDynamic, FindPcdsDynamicEx) = \
463                 (False, False, True, False, False, False, False)
464                continue
465            if Line.find('<PcdsPatchableInModule>') != -1:
466                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
467                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
468                 FindPcdsDynamic, FindPcdsDynamicEx) = \
469                 (False, False, False, True, False, False, False)
470                continue
471            if Line.find('<PcdsFixedAtBuild>') != -1:
472                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
473                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
474                 FindPcdsDynamic, FindPcdsDynamicEx) = \
475                 (False, False, False, False, True, False, False)
476                continue
477            if Line.find('<PcdsDynamic>') != -1:
478                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
479                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
480                 FindPcdsDynamic, FindPcdsDynamicEx) = \
481                 (False, False, False, False, False, True, False)
482                continue
483            if Line.find('<PcdsDynamicEx>') != -1:
484                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
485                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
486                 FindPcdsDynamic, FindPcdsDynamicEx) = \
487                 (False, False, False, False, False, False, True)
488                continue
489            if Line.endswith('}'):
490                #
491                # find '}' at line tail
492                #
493                KeyValues.append([ListItem, LibraryClassItem, BuildOption, \
494                                  Pcd])
495                (FindBlock, FindLibraryClass, FindBuildOption, \
496                 FindPcdsFeatureFlag, FindPcdsPatchableInModule, \
497                 FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \
498                 (False, False, False, False, False, False, False, False)
499                LibraryClassItem, BuildOption, Pcd = [], [], []
500                continue
501
502        if FindBlock:
503            if FindLibraryClass:
504                LibraryClassItem.append(Line)
505            elif FindBuildOption:
506                BuildOption.append(Line)
507            elif FindPcdsFeatureFlag:
508                Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line))
509            elif FindPcdsPatchableInModule:
510                Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line))
511            elif FindPcdsFixedAtBuild:
512                Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line))
513            elif FindPcdsDynamic:
514                Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line))
515            elif FindPcdsDynamicEx:
516                Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line))
517        else:
518            KeyValues.append([ListItem, [], [], []])
519
520    return True
521
522## Get Source
523#
524# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>
525# [|<PcdFeatureFlag>]]]]
526#
527# @param Item:           String as <Filename>[|<Family>[|<TagName>[|<ToolCode>
528#                        [|<PcdFeatureFlag>]]]]
529# @param ContainerFile:  The file which describes the library class, used
530#                        for error report
531#
532def GetSource(Item, ContainerFile, FileRelativePath, LineNo= -1):
533    ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4
534    List = GetSplitValueList(ItemNew)
535    if len(List) < 5 or len(List) > 9:
536        RaiseParserError(Item, 'Sources', ContainerFile, \
537                         '<Filename>[|<Family>[|<TagName>[|<ToolCode>\
538                         [|<PcdFeatureFlag>]]]]', LineNo)
539    List[0] = NormPath(List[0])
540    CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', \
541                   Item, LineNo)
542    if List[4] != '':
543        CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo)
544
545    return (List[0], List[1], List[2], List[3], List[4])
546
547## Get Binary
548#
549# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>
550# [|<PcdFeatureFlag>]]]]
551#
552# @param Item:           String as <Filename>[|<Family>[|<TagName>
553#                        [|<ToolCode>[|<PcdFeatureFlag>]]]]
554# @param ContainerFile:  The file which describes the library class,
555#                        used for error report
556#
557def GetBinary(Item, ContainerFile, LineNo= -1):
558    ItemNew = Item + DataType.TAB_VALUE_SPLIT
559    List = GetSplitValueList(ItemNew)
560    if len(List) < 3 or len(List) > 5:
561        RaiseParserError(Item, 'Binaries', ContainerFile, \
562                         "<FileType>|<Filename>[|<Target>\
563                         [|<TokenSpaceGuidCName>.<PcdCName>]]", LineNo)
564
565    if len(List) >= 4:
566        if List[3] != '':
567            CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo)
568        return (List[0], List[1], List[2], List[3])
569    elif len(List) == 3:
570        return (List[0], List[1], List[2], '')
571
572## Get Guids/Protocols/Ppis
573#
574# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
575#
576# @param Item:           String as <GuidCName>[|<PcdFeatureFlag>]
577# @param Type:           Type of parsing string
578# @param ContainerFile:  The file which describes the library class,
579#                        used for error report
580#
581def GetGuidsProtocolsPpisOfInf(Item):
582    ItemNew = Item + DataType.TAB_VALUE_SPLIT
583    List = GetSplitValueList(ItemNew)
584    return (List[0], List[1])
585
586## Get Guids/Protocols/Ppis
587#
588# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
589#
590# @param Item:           String as <GuidCName>=<GuidValue>
591# @param Type:           Type of parsing string
592# @param ContainerFile:  The file which describes the library class,
593# used for error report
594#
595def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo= -1):
596    List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT)
597    if len(List) != 2:
598        RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', \
599                         LineNo)
600    #
601    #convert C-Format Guid to Register Format
602    #
603    if List[1][0] == '{' and List[1][-1] == '}':
604        RegisterFormatGuid = GuidStructureStringToGuidString(List[1])
605        if RegisterFormatGuid == '':
606            RaiseParserError(Item, Type, ContainerFile, \
607                             'CFormat or RegisterFormat', LineNo)
608    else:
609        if CheckGuidRegFormat(List[1]):
610            RegisterFormatGuid = List[1]
611        else:
612            RaiseParserError(Item, Type, ContainerFile, \
613                             'CFormat or RegisterFormat', LineNo)
614
615    return (List[0], RegisterFormatGuid)
616
617## GetPackage
618#
619# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
620#
621# @param Item:           String as <PackagePath>[|<PcdFeatureFlag>]
622# @param Type:           Type of parsing string
623# @param ContainerFile:  The file which describes the library class,
624#                        used for error report
625#
626def GetPackage(Item, ContainerFile, FileRelativePath, LineNo= -1):
627    ItemNew = Item + DataType.TAB_VALUE_SPLIT
628    List = GetSplitValueList(ItemNew)
629    CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo)
630    CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', \
631                   List[0], LineNo)
632    if List[1] != '':
633        CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo)
634
635    return (List[0], List[1])
636
637## Get Pcd Values of Inf
638#
639# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>]
640#
641# @param Item:  The string describes pcd
642# @param Type:  The type of Pcd
643# @param File:  The file which describes the pcd, used for error report
644#
645def GetPcdOfInf(Item, Type, File, LineNo):
646    Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]'
647    TokenGuid, TokenName, Value, InfType = '', '', '', ''
648
649    if Type == DataType.TAB_PCDS_FIXED_AT_BUILD:
650        InfType = DataType.TAB_INF_FIXED_PCD
651    elif Type == DataType.TAB_PCDS_PATCHABLE_IN_MODULE:
652        InfType = DataType.TAB_INF_PATCH_PCD
653    elif Type == DataType.TAB_PCDS_FEATURE_FLAG:
654        InfType = DataType.TAB_INF_FEATURE_PCD
655    elif Type == DataType.TAB_PCDS_DYNAMIC_EX:
656        InfType = DataType.TAB_INF_PCD_EX
657    elif Type == DataType.TAB_PCDS_DYNAMIC:
658        InfType = DataType.TAB_INF_PCD
659    List = GetSplitValueList(Item, DataType.TAB_VALUE_SPLIT, 1)
660    TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
661    if len(TokenInfo) != 2:
662        RaiseParserError(Item, InfType, File, Format, LineNo)
663    else:
664        TokenGuid = TokenInfo[0]
665        TokenName = TokenInfo[1]
666
667    if len(List) > 1:
668        Value = List[1]
669    else:
670        Value = None
671    return (TokenGuid, TokenName, Value, InfType)
672
673
674## Get Pcd Values of Dec
675#
676# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>
677# @param Item:  Pcd item
678# @param Type:  Pcd type
679# @param File:  Dec file
680# @param LineNo:  Line number
681#
682def GetPcdOfDec(Item, Type, File, LineNo= -1):
683    Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>'
684    TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', ''
685    List = GetSplitValueList(Item)
686    if len(List) != 4:
687        RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
688    else:
689        Value = List[1]
690        DatumType = List[2]
691        Token = List[3]
692    TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
693    if len(TokenInfo) != 2:
694        RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
695    else:
696        TokenGuid = TokenInfo[0]
697        TokenName = TokenInfo[1]
698
699    return (TokenGuid, TokenName, Value, DatumType, Token, Type)
700
701## Parse DEFINE statement
702#
703# Get DEFINE macros
704#
705# @param LineValue:  A DEFINE line value
706# @param StartLine:  A DEFINE start line
707# @param Table:      A table
708# @param FileID:     File ID
709# @param Filename:   File name
710# @param SectionName:  DEFINE section name
711# @param SectionModel:  DEFINE section model
712# @param Arch:   DEFINE arch
713#
714def ParseDefine(LineValue, StartLine, Table, FileID, SectionName, \
715                SectionModel, Arch):
716    Logger.Debug(Logger.DEBUG_2, ST.MSG_DEFINE_STATEMENT_FOUND % (LineValue, \
717                                                                  SectionName))
718    Define = \
719    GetSplitValueList(CleanString\
720                      (LineValue[LineValue.upper().\
721                                 find(DataType.TAB_DEFINE.upper() + ' ') + \
722                                 len(DataType.TAB_DEFINE + ' ') : ]), \
723                                 DataType.TAB_EQUAL_SPLIT, 1)
724    Table.Insert(DataType.MODEL_META_DATA_DEFINE, Define[0], Define[1], '', \
725                 '', '', Arch, SectionModel, FileID, StartLine, -1, \
726                 StartLine, -1, 0)
727
728## InsertSectionItems
729#
730# Insert item data of a section to a dict
731#
732# @param Model:   A model
733# @param CurrentSection:   Current section
734# @param SectionItemList:   Section item list
735# @param ArchList:   Arch list
736# @param ThirdList:   Third list
737# @param RecordSet:   Record set
738#
739def InsertSectionItems(Model, SectionItemList, ArchList, \
740                       ThirdList, RecordSet):
741    #
742    # Insert each item data of a section
743    #
744    for Index in range(0, len(ArchList)):
745        Arch = ArchList[Index]
746        Third = ThirdList[Index]
747        if Arch == '':
748            Arch = DataType.TAB_ARCH_COMMON
749
750        Records = RecordSet[Model]
751        for SectionItem in SectionItemList:
752            LineValue, StartLine, Comment = SectionItem[0], \
753            SectionItem[1], SectionItem[2]
754
755            Logger.Debug(4, ST.MSG_PARSING % LineValue)
756            #
757            # And then parse DEFINE statement
758            #
759            if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
760                continue
761            #
762            # At last parse other sections
763            #
764            IdNum = -1
765            Records.append([LineValue, Arch, StartLine, IdNum, Third, Comment])
766
767        if RecordSet != {}:
768            RecordSet[Model] = Records
769
770## GenMetaDatSectionItem
771#
772# @param Key:    A key
773# @param Value:  A value
774# @param List:   A list
775#
776def GenMetaDatSectionItem(Key, Value, List):
777    if Key not in List:
778        List[Key] = [Value]
779    else:
780        List[Key].append(Value)
781
782## GetPkgInfoFromDec
783#
784# get package name, guid, version info from dec files
785#
786# @param Path:   File path
787#
788def GetPkgInfoFromDec(Path):
789    PkgName = None
790    PkgGuid = None
791    PkgVersion = None
792
793    Path = Path.replace('\\', '/')
794
795    if not os.path.exists(Path):
796        Logger.Error("\nUPT", FILE_NOT_FOUND, File=Path)
797
798    if Path in gPKG_INFO_DICT:
799        return gPKG_INFO_DICT[Path]
800
801    try:
802        DecParser = None
803        if Path not in GlobalData.gPackageDict:
804            DecParser = Dec(Path)
805            GlobalData.gPackageDict[Path] = DecParser
806        else:
807            DecParser = GlobalData.gPackageDict[Path]
808
809        PkgName = DecParser.GetPackageName()
810        PkgGuid = DecParser.GetPackageGuid()
811        PkgVersion = DecParser.GetPackageVersion()
812        gPKG_INFO_DICT[Path] = (PkgName, PkgGuid, PkgVersion)
813        return PkgName, PkgGuid, PkgVersion
814    except FatalError:
815        return None, None, None
816
817
818## GetWorkspacePackage
819#
820# Get a list of workspace package information.
821#
822def GetWorkspacePackage():
823    DecFileList = []
824    WorkspaceDir = GlobalData.gWORKSPACE
825    PackageDir = GlobalData.gPACKAGE_PATH
826    for PkgRoot in [WorkspaceDir] + PackageDir:
827        for Root, Dirs, Files in os.walk(PkgRoot):
828            if 'CVS' in Dirs:
829                Dirs.remove('CVS')
830            if '.svn' in Dirs:
831                Dirs.remove('.svn')
832            for Dir in Dirs:
833                if Dir.startswith('.'):
834                    Dirs.remove(Dir)
835            for FileSp in Files:
836                if FileSp.startswith('.'):
837                    continue
838                Ext = os.path.splitext(FileSp)[1]
839                if Ext.lower() in ['.dec']:
840                    DecFileList.append\
841                    (os.path.normpath(os.path.join(Root, FileSp)))
842    #
843    # abstract package guid, version info from DecFile List
844    #
845    PkgList = []
846    for DecFile in DecFileList:
847        (PkgName, PkgGuid, PkgVersion) = GetPkgInfoFromDec(DecFile)
848        if PkgName and PkgGuid and PkgVersion:
849            PkgList.append((PkgName, PkgGuid, PkgVersion, DecFile))
850
851    return PkgList
852
853## GetWorkspaceModule
854#
855# Get a list of workspace modules.
856#
857def GetWorkspaceModule():
858    InfFileList = []
859    WorkspaceDir = GlobalData.gWORKSPACE
860    for Root, Dirs, Files in os.walk(WorkspaceDir):
861        if 'CVS' in Dirs:
862            Dirs.remove('CVS')
863        if '.svn' in Dirs:
864            Dirs.remove('.svn')
865        if 'Build' in Dirs:
866            Dirs.remove('Build')
867        for Dir in Dirs:
868            if Dir.startswith('.'):
869                Dirs.remove(Dir)
870        for FileSp in Files:
871            if FileSp.startswith('.'):
872                continue
873            Ext = os.path.splitext(FileSp)[1]
874            if Ext.lower() in ['.inf']:
875                InfFileList.append\
876                (os.path.normpath(os.path.join(Root, FileSp)))
877
878    return InfFileList
879
880## MacroParser used to parse macro definition
881#
882# @param Line:            The content contain linestring and line number
883# @param FileName:        The meta-file file name
884# @param SectionType:     Section for the Line belong to
885# @param FileLocalMacros: A list contain Macro defined in [Defines] section.
886#
887def MacroParser(Line, FileName, SectionType, FileLocalMacros):
888    MacroDefPattern = re.compile("^(DEFINE)[ \t]+")
889    LineContent = Line[0]
890    LineNo = Line[1]
891    Match = MacroDefPattern.match(LineContent)
892    if not Match:
893        #
894        # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
895        #
896        return None, None
897
898    TokenList = GetSplitValueList(LineContent[Match.end(1):], \
899                                  DataType.TAB_EQUAL_SPLIT, 1)
900    #
901    # Syntax check
902    #
903    if not TokenList[0]:
904        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACRONAME_NOGIVEN,
905                        ExtraData=LineContent, File=FileName, Line=LineNo)
906    if len(TokenList) < 2:
907        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACROVALUE_NOGIVEN,
908                        ExtraData=LineContent, File=FileName, Line=LineNo)
909
910    Name, Value = TokenList
911
912    #
913    # DEFINE defined macros
914    #
915    if SectionType == DataType.MODEL_META_DATA_HEADER:
916        FileLocalMacros[Name] = Value
917
918    ReIsValidMacroName = re.compile(r"^[A-Z][A-Z0-9_]*$", re.DOTALL)
919    if ReIsValidMacroName.match(Name) is None:
920        Logger.Error('Parser',
921                     FORMAT_INVALID,
922                     ST.ERR_MACRONAME_INVALID % (Name),
923                     ExtraData=LineContent,
924                     File=FileName,
925                     Line=LineNo)
926
927    # Validate MACRO Value
928    #
929    # <MacroDefinition> ::=  [<Comments>]{0,}
930    #                       "DEFINE" <MACRO> "=" [{<PATH>} {<VALUE>}] <EOL>
931    # <Value>           ::=  {<NumVal>} {<Boolean>} {<AsciiString>} {<GUID>}
932    #                        {<CString>} {<UnicodeString>} {<CArray>}
933    #
934    # The definition of <NumVal>, <PATH>, <Boolean>, <GUID>, <CString>,
935    # <UnicodeString>, <CArray> are subset of <AsciiString>.
936    #
937    ReIsValidMacroValue = re.compile(r"^[\x20-\x7e]*$", re.DOTALL)
938    if ReIsValidMacroValue.match(Value) is None:
939        Logger.Error('Parser',
940                     FORMAT_INVALID,
941                     ST.ERR_MACROVALUE_INVALID % (Value),
942                     ExtraData=LineContent,
943                     File=FileName,
944                     Line=LineNo)
945
946    return Name, Value
947
948## GenSection
949#
950# generate section contents
951#
952# @param  SectionName:  indicate the name of the section, details refer to
953#                       INF, DEC specs
954# @param  SectionDict:  section statement dict, key is SectionAttrs(arch,
955#                       moduletype or platform may exist as needed) list
956#                       separated by space,
957#                       value is statement
958#
959def GenSection(SectionName, SectionDict, SplitArch=True, NeedBlankLine=False):
960    Content = ''
961    for SectionAttrs in SectionDict:
962        StatementList = SectionDict[SectionAttrs]
963        if SectionAttrs and SectionName != 'Defines' and SectionAttrs.strip().upper() != DataType.TAB_ARCH_COMMON:
964            if SplitArch:
965                ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_SPACE_SPLIT)
966            else:
967                if SectionName != 'UserExtensions':
968                    ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_COMMENT_SPLIT)
969                else:
970                    ArchList = [SectionAttrs]
971            for Index in range(0, len(ArchList)):
972                ArchList[Index] = ConvertArchForInstall(ArchList[Index])
973            Section = '[' + SectionName + '.' + (', ' + SectionName + '.').join(ArchList) + ']'
974        else:
975            Section = '[' + SectionName + ']'
976        Content += '\n' + Section + '\n'
977        if StatementList is not None:
978            for Statement in StatementList:
979                LineList = Statement.split('\n')
980                NewStatement = ""
981                for Line in LineList:
982                    # ignore blank comment
983                    if not Line.replace("#", '').strip() and SectionName not in ('Defines', 'Hob', 'Event', 'BootMode'):
984                        continue
985                    # add two space before non-comments line except the comments in Defines section
986                    if Line.strip().startswith('#') and SectionName == 'Defines':
987                        NewStatement += "%s\n" % Line
988                        continue
989                    NewStatement += "  %s\n" % Line
990                if NeedBlankLine:
991                    Content += NewStatement + '\n'
992                else:
993                    Content += NewStatement
994
995        if NeedBlankLine:
996            Content = Content[:-1]
997    if not Content.replace('\\n', '').strip():
998        return ''
999    return Content
1000
1001## ConvertArchForInstall
1002# if Arch.upper() is in "IA32", "X64", "IPF", and "EBC", it must be upper case.  "common" must be lower case.
1003# Anything else, the case must be preserved
1004#
1005# @param Arch: the arch string that need to be converted, it should be stripped before pass in
1006# @return: the arch string that get converted
1007#
1008def ConvertArchForInstall(Arch):
1009    if Arch.upper() in [DataType.TAB_ARCH_IA32, DataType.TAB_ARCH_X64,
1010                                   DataType.TAB_ARCH_IPF, DataType.TAB_ARCH_EBC]:
1011        Arch = Arch.upper()
1012    elif Arch.upper() == DataType.TAB_ARCH_COMMON:
1013        Arch = Arch.lower()
1014
1015    return Arch
1016