1## @file
2# This file contained the parser for sections in INF file
3#
4# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5#
6# SPDX-License-Identifier: BSD-2-Clause-Patent
7#
8
9'''
10InfSectionParser
11'''
12##
13# Import Modules
14#
15from copy import deepcopy
16import re
17
18from Library.StringUtils import GetSplitValueList
19from Library.CommentParsing import ParseHeaderCommentSection
20from Library.CommentParsing import ParseComment
21
22from Library import DataType as DT
23
24import Logger.Log as Logger
25from Logger import StringTable as ST
26from Logger.ToolError import FORMAT_INVALID
27
28from Object.Parser.InfDefineObject import InfDefObject
29from Object.Parser.InfBuildOptionObject import InfBuildOptionsObject
30from Object.Parser.InfLibraryClassesObject import InfLibraryClassObject
31from Object.Parser.InfPackagesObject import InfPackageObject
32from Object.Parser.InfPcdObject import InfPcdObject
33from Object.Parser.InfSoucesObject import InfSourcesObject
34from Object.Parser.InfUserExtensionObject import InfUserExtensionObject
35from Object.Parser.InfProtocolObject import InfProtocolObject
36from Object.Parser.InfPpiObject import InfPpiObject
37from Object.Parser.InfGuidObject import InfGuidObject
38from Object.Parser.InfDepexObject import InfDepexObject
39from Object.Parser.InfBinaryObject import InfBinariesObject
40from Object.Parser.InfHeaderObject import InfHeaderObject
41from Object.Parser.InfMisc import InfSpecialCommentObject
42from Object.Parser.InfMisc import InfHobObject
43from Object.Parser.InfMisc import InfBootModeObject
44from Object.Parser.InfMisc import InfEventObject
45from Parser.InfParserMisc import gINF_SECTION_DEF
46from Parser.InfDefineSectionParser import InfDefinSectionParser
47from Parser.InfBuildOptionSectionParser import InfBuildOptionSectionParser
48from Parser.InfSourceSectionParser import InfSourceSectionParser
49from Parser.InfLibrarySectionParser import InfLibrarySectionParser
50from Parser.InfPackageSectionParser import InfPackageSectionParser
51from Parser.InfGuidPpiProtocolSectionParser import InfGuidPpiProtocolSectionParser
52from Parser.InfBinarySectionParser import InfBinarySectionParser
53from Parser.InfPcdSectionParser import InfPcdSectionParser
54from Parser.InfDepexSectionParser import InfDepexSectionParser
55
56## GetSpecialStr2
57#
58# GetSpecialStr2
59#
60def GetSpecialStr2(ItemList, FileName, LineNo, SectionString):
61    Str2 = ''
62    #
63    # S2 may be Platform or ModuleType
64    #
65    if len(ItemList) == 3:
66        #
67        # Except [LibraryClass], [Depex]
68        # section can has more than 2 items in section header string,
69        # others should report error.
70        #
71        if not (ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() or \
72                ItemList[0].upper() == DT.TAB_DEPEX.upper() or \
73                ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper()):
74            if ItemList[2] != '':
75                Logger.Error('Parser',
76                             FORMAT_INVALID,
77                             ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID % (SectionString),
78                             File=FileName,
79                             Line=LineNo,
80                             ExtraData=SectionString)
81        Str2 = ItemList[2]
82    elif len(ItemList) == 4:
83        #
84        # Except [UserExtension]
85        # section can has 4 items in section header string,
86        # others should report error.
87        #
88        if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper() or ItemList[0].upper() == DT.TAB_DEPEX.upper():
89            if ItemList[3] != '':
90                Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \
91                             % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString)
92
93        if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper():
94            Str2 = ItemList[2] + ' | ' + ItemList[3]
95        else:
96            Str2 = ItemList[2]
97
98    elif len(ItemList) > 4:
99        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_INF_PARSER_SOURCE_SECTION_SECTIONNAME_INVALID \
100                     % (SectionString), File=FileName, Line=LineNo, ExtraData=SectionString)
101
102    return Str2
103
104## ProcessUseExtHeader
105#
106#
107def ProcessUseExtHeader(ItemList):
108    NewItemList = []
109    AppendContent = ''
110    CompleteFlag = False
111    for Item in ItemList:
112        if Item.startswith('\"') and not Item.endswith('\"'):
113            AppendContent = Item
114            CompleteFlag = True
115        elif Item.endswith('\"') and not Item.startswith('\"'):
116            #
117            # Should not have an userId or IdString not starts with " before but ends with ".
118            #
119            if not CompleteFlag:
120                return False, []
121            AppendContent = AppendContent + "." + Item
122            NewItemList.append(AppendContent)
123            CompleteFlag = False
124            AppendContent = ''
125        elif Item.endswith('\"') and Item.startswith('\"'):
126            #
127            # Common item, not need to combine the information
128            #
129            NewItemList.append(Item)
130        else:
131            if not CompleteFlag:
132                NewItemList.append(Item)
133            else:
134                AppendContent = AppendContent + "." + Item
135
136    if len(NewItemList) > 4:
137        return False, []
138
139    return True, NewItemList
140
141## GetArch
142#
143# GetArch
144#
145def GetArch(ItemList, ArchList, FileName, LineNo, SectionString):
146    #
147    # S1 is always Arch
148    #
149    if len(ItemList) > 1:
150        Arch = ItemList[1]
151    else:
152        Arch = 'COMMON'
153    ArchList.add(Arch)
154
155    #
156    # 'COMMON' must not be used with specific ARCHs at the same section
157    #
158    if 'COMMON' in ArchList and len(ArchList) > 1:
159        Logger.Error('Parser',
160                     FORMAT_INVALID,
161                     ST.ERR_INF_PARSER_SECTION_ARCH_CONFLICT,
162                     File=FileName,
163                     Line=LineNo,
164                     ExtraData=SectionString)
165
166    return Arch, ArchList
167
168## InfSectionParser
169#
170# Inherit from object
171#
172class InfSectionParser(InfDefinSectionParser,
173                       InfBuildOptionSectionParser,
174                       InfSourceSectionParser,
175                       InfLibrarySectionParser,
176                       InfPackageSectionParser,
177                       InfGuidPpiProtocolSectionParser,
178                       InfBinarySectionParser,
179                       InfPcdSectionParser,
180                       InfDepexSectionParser):
181    #
182    # Parser objects used to implement singleton
183    #
184    MetaFiles = {}
185
186    ## Factory method
187    #
188    # One file, one parser object. This factory method makes sure that there's
189    # only one object constructed for one meta file.
190    #
191    #   @param  Class           class object of real AutoGen class
192    #                           (InfParser, DecParser or DscParser)
193    #   @param  FilePath        The path of meta file
194    #
195    def __new__(cls, FilePath, *args, **kwargs):
196        if args:
197            pass
198        if kwargs:
199            pass
200        if FilePath in cls.MetaFiles:
201            return cls.MetaFiles[FilePath]
202        else:
203            ParserObject = super(InfSectionParser, cls).__new__(cls)
204            cls.MetaFiles[FilePath] = ParserObject
205            return ParserObject
206
207    def __init__(self):
208        InfDefinSectionParser.__init__(self)
209        InfBuildOptionSectionParser.__init__(self)
210        InfSourceSectionParser.__init__(self)
211        InfLibrarySectionParser.__init__(self)
212        InfPackageSectionParser.__init__(self)
213        InfGuidPpiProtocolSectionParser.__init__(self)
214        InfBinarySectionParser.__init__(self)
215        InfPcdSectionParser.__init__(self)
216        InfDepexSectionParser.__init__(self)
217        #
218        # Initialize all objects that an INF file will generated.
219        #
220        self.InfDefSection = InfDefObject()
221        self.InfBuildOptionSection = InfBuildOptionsObject()
222        self.InfLibraryClassSection = InfLibraryClassObject()
223        self.InfPackageSection = InfPackageObject()
224        self.InfPcdSection = InfPcdObject(list(self.MetaFiles.keys())[0])
225        self.InfSourcesSection = InfSourcesObject()
226        self.InfUserExtensionSection = InfUserExtensionObject()
227        self.InfProtocolSection = InfProtocolObject()
228        self.InfPpiSection = InfPpiObject()
229        self.InfGuidSection = InfGuidObject()
230        self.InfDepexSection = InfDepexObject()
231        self.InfPeiDepexSection = InfDepexObject()
232        self.InfDxeDepexSection = InfDepexObject()
233        self.InfSmmDepexSection = InfDepexObject()
234        self.InfBinariesSection = InfBinariesObject()
235        self.InfHeader = InfHeaderObject()
236        self.InfBinaryHeader = InfHeaderObject()
237        self.InfSpecialCommentSection = InfSpecialCommentObject()
238
239        #
240        # A List for store define section content.
241        #
242        self._PcdNameList = []
243        self._SectionName = ''
244        self._SectionType = 0
245        self.RelaPath = ''
246        self.FileName = ''
247
248    #
249    # File Header content parser
250    #
251    def InfHeaderParser(self, Content, InfHeaderObject2, FileName, IsBinaryHeader = False):
252        if IsBinaryHeader:
253            (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName, True)
254            if not Abstract or not Description or not Copyright or not License:
255                Logger.Error('Parser',
256                             FORMAT_INVALID,
257                             ST.ERR_INVALID_BINARYHEADER_FORMAT,
258                             File=FileName)
259        else:
260            (Abstract, Description, Copyright, License) = ParseHeaderCommentSection(Content, FileName)
261        #
262        # Not process file name now, for later usage.
263        #
264        if self.FileName:
265            pass
266
267        #
268        # Insert Abstract, Description, CopyRight, License into header object
269        #
270        InfHeaderObject2.SetAbstract(Abstract)
271        InfHeaderObject2.SetDescription(Description)
272        InfHeaderObject2.SetCopyright(Copyright)
273        InfHeaderObject2.SetLicense(License)
274
275
276
277
278    ## Section header parser
279    #
280    #   The section header is always in following format:
281    #
282    #       [section_name.arch<.platform|module_type>]
283    #
284    # @param String    A string contained the content need to be parsed.
285    #
286    def SectionHeaderParser(self, SectionString, FileName, LineNo):
287        _Scope = []
288        _SectionName = ''
289        ArchList = set()
290        _ValueList = []
291        _PcdNameList = [DT.TAB_INF_FIXED_PCD.upper(),
292                             DT.TAB_INF_FEATURE_PCD.upper(),
293                             DT.TAB_INF_PATCH_PCD.upper(),
294                             DT.TAB_INF_PCD.upper(),
295                             DT.TAB_INF_PCD_EX.upper()
296                             ]
297        SectionString = SectionString.strip()
298        for Item in GetSplitValueList(SectionString[1:-1], DT.TAB_COMMA_SPLIT):
299            if Item == '':
300                Logger.Error('Parser',
301                             FORMAT_INVALID,
302                             ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""),
303                             File=FileName,
304                             Line=LineNo,
305                             ExtraData=SectionString)
306            ItemList = GetSplitValueList(Item, DT.TAB_SPLIT)
307            #
308            # different section should not mix in one section
309            # Allow different PCD type sections mixed together
310            #
311            if _SectionName.upper() not in _PcdNameList:
312                if _SectionName != '' and _SectionName.upper() != ItemList[0].upper():
313                    Logger.Error('Parser',
314                                 FORMAT_INVALID,
315                                 ST.ERR_INF_PARSER_SECTION_NAME_DUPLICATE,
316                                 File=FileName,
317                                 Line=LineNo,
318                                 ExtraData=SectionString)
319            elif _PcdNameList[1] in [_SectionName.upper(), ItemList[0].upper()] and \
320                (_SectionName.upper()!= ItemList[0].upper()):
321                Logger.Error('Parser',
322                             FORMAT_INVALID,
323                             ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (""),
324                             File=FileName,
325                             Line=LineNo,
326                             ExtraData=SectionString)
327
328            _SectionName = ItemList[0]
329            if _SectionName.upper() in gINF_SECTION_DEF:
330                self._SectionType = gINF_SECTION_DEF[_SectionName.upper()]
331            else:
332                self._SectionType = DT.MODEL_UNKNOWN
333                Logger.Error("Parser",
334                             FORMAT_INVALID,
335                             ST.ERR_INF_PARSER_UNKNOWN_SECTION,
336                             File=FileName,
337                             Line=LineNo,
338                             ExtraData=SectionString)
339
340            #
341            # Get Arch
342            #
343            Str1, ArchList = GetArch(ItemList, ArchList, FileName, LineNo, SectionString)
344
345            #
346            # For [Defines] section, do special check.
347            #
348            if ItemList[0].upper() == DT.TAB_COMMON_DEFINES.upper():
349                if len(ItemList) != 1:
350                    Logger.Error('Parser',
351                                 FORMAT_INVALID,
352                                 ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString),
353                                 File=FileName, Line=LineNo, ExtraData=SectionString)
354
355            #
356            # For [UserExtension] section, do special check.
357            #
358            if ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper():
359
360                RetValue = ProcessUseExtHeader(ItemList)
361
362                if not RetValue[0]:
363                    Logger.Error('Parser',
364                                 FORMAT_INVALID,
365                                 ST.ERR_INF_PARSER_DEFINE_FROMAT_INVALID % (SectionString),
366                                 File=FileName, Line=LineNo, ExtraData=SectionString)
367                else:
368                    ItemList = RetValue[1]
369
370                if len(ItemList) == 3:
371                    ItemList.append('COMMON')
372
373                Str1 = ItemList[1]
374
375            #
376            # For Library classes, need to check module type.
377            #
378            if ItemList[0].upper() == DT.TAB_LIBRARY_CLASSES.upper() and len(ItemList) == 3:
379                if ItemList[2] != '':
380                    ModuleTypeList = GetSplitValueList(ItemList[2], DT.TAB_VALUE_SPLIT)
381                    for Item in ModuleTypeList:
382                        if Item.strip() not in DT.MODULE_LIST:
383                            Logger.Error('Parser',
384                                         FORMAT_INVALID,
385                                         ST.ERR_INF_PARSER_DEFINE_MODULETYPE_INVALID % (Item),
386                                         File=FileName,
387                                         Line=LineNo,
388                                         ExtraData=SectionString)
389            #
390            # GetSpecialStr2
391            #
392            Str2 = GetSpecialStr2(ItemList, FileName, LineNo, SectionString)
393
394            _Scope.append([Str1, Str2])
395
396            _NewValueList = []
397            _AppendFlag = True
398            if _SectionName.upper() in _PcdNameList:
399                for ValueItem in _ValueList:
400                    if _SectionName.upper() == ValueItem[0].upper() and Str1.upper() not in ValueItem[1].split():
401                        ValueItem[1] = ValueItem[1] + " " + Str1
402                        _AppendFlag = False
403                    elif _SectionName.upper() == ValueItem[0].upper() and Str1.upper() in ValueItem[1].split():
404                        _AppendFlag = False
405
406                    _NewValueList.append(ValueItem)
407
408                _ValueList = _NewValueList
409
410            if _AppendFlag:
411                if not ItemList[0].upper() == DT.TAB_USER_EXTENSIONS.upper():
412                    _ValueList.append([_SectionName, Str1, Str2, LineNo])
413                else:
414                    if len(ItemList) == 4:
415                        _ValueList.append([_SectionName, Str1, Str2, ItemList[3], LineNo])
416
417        self.SectionHeaderContent = deepcopy(_ValueList)
418
419    ## GenSpecialSectionList
420    #
421    #  @param SpecialSectionList: a list of list, of which item's format
422    #                             (Comment, LineNum)
423    #  @param ContainerFile:      Input value for filename of Inf file
424    #
425    def InfSpecialCommentParser (self, SpecialSectionList, InfSectionObject, ContainerFile, SectionType):
426        ReFindSpecialCommentRe = re.compile(r"""#(?:\s*)\[(.*?)\](?:.*)""", re.DOTALL)
427        ReFindHobArchRe = re.compile(r"""[Hh][Oo][Bb]\.([^,]*)""", re.DOTALL)
428        if self.FileName:
429            pass
430        SpecialObjectList = []
431        ArchList = []
432        if SectionType == DT.TYPE_EVENT_SECTION:
433            TokenDict = DT.EVENT_TOKENS
434        elif SectionType == DT.TYPE_HOB_SECTION:
435            TokenDict = DT.HOB_TOKENS
436        else:
437            TokenDict = DT.BOOTMODE_TOKENS
438
439        for List in SpecialSectionList:
440            #
441            # Hob has Arch attribute, need to be handled specially here
442            #
443            if SectionType == DT.TYPE_HOB_SECTION:
444
445                MatchObject = ReFindSpecialCommentRe.search(List[0][0])
446                HobSectionStr = MatchObject.group(1)
447                ArchList = []
448                for Match in ReFindHobArchRe.finditer(HobSectionStr):
449                    Arch = Match.groups(1)[0].upper()
450                    ArchList.append(Arch)
451            CommentSoFar = ''
452            for Index in range(1, len(List)):
453                Result = ParseComment(List[Index], DT.ALL_USAGE_TOKENS, TokenDict, [], False)
454                Usage = Result[0]
455                Type = Result[1]
456                HelpText = Result[3]
457
458                if Usage == DT.ITEM_UNDEFINED and Type == DT.ITEM_UNDEFINED:
459                    if HelpText is None:
460                        HelpText = ''
461                    if not HelpText.endswith('\n'):
462                        HelpText += '\n'
463                    CommentSoFar += HelpText
464                else:
465                    if HelpText:
466                        CommentSoFar += HelpText
467                    if SectionType == DT.TYPE_EVENT_SECTION:
468                        SpecialObject = InfEventObject()
469                        SpecialObject.SetEventType(Type)
470                        SpecialObject.SetUsage(Usage)
471                        SpecialObject.SetHelpString(CommentSoFar)
472                    elif SectionType == DT.TYPE_HOB_SECTION:
473                        SpecialObject = InfHobObject()
474                        SpecialObject.SetHobType(Type)
475                        SpecialObject.SetUsage(Usage)
476                        SpecialObject.SetHelpString(CommentSoFar)
477                        if len(ArchList) >= 1:
478                            SpecialObject.SetSupArchList(ArchList)
479                    else:
480                        SpecialObject = InfBootModeObject()
481                        SpecialObject.SetSupportedBootModes(Type)
482                        SpecialObject.SetUsage(Usage)
483                        SpecialObject.SetHelpString(CommentSoFar)
484
485                    SpecialObjectList.append(SpecialObject)
486                    CommentSoFar = ''
487        if not InfSectionObject.SetSpecialComments(SpecialObjectList,
488                                                   SectionType):
489            Logger.Error('InfParser',
490                         FORMAT_INVALID,
491                         ST.ERR_INF_PARSER_MODULE_SECTION_TYPE_ERROR % (SectionType),
492                         ContainerFile
493                         )
494