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