1## @file
2# This file is used to define class objects of INF file [Ppis] section.
3# It will consumed by InfParser.
4#
5# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
6#
7# This program and the accompanying materials are licensed and made available
8# under the terms and conditions of the BSD License which accompanies this
9# distribution. The full text of the license may be found at
10# http://opensource.org/licenses/bsd-license.php
11#
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15'''
16InfPpiObject
17'''
18
19from Library.ParserValidate import IsValidCVariableName
20from Library.CommentParsing import ParseComment
21from Library.ExpressionValidate import IsValidFeatureFlagExp
22
23from Library.Misc import Sdict
24from Library import DataType as DT
25import Logger.Log as Logger
26from Logger import ToolError
27from Logger import StringTable as ST
28
29def ParsePpiComment(CommentsList, InfPpiItemObj):
30    PreNotify = None
31    PreUsage = None
32    PreHelpText = ''
33    BlockFlag = -1
34    CommentInsList = []
35    Count = 0
36    for CommentItem in CommentsList:
37        Count = Count + 1
38        CommentItemUsage, \
39        CommentItemNotify, \
40        CommentItemString, \
41        CommentItemHelpText = \
42                ParseComment(CommentItem,
43                             DT.ALL_USAGE_TOKENS,
44                             DT.PPI_NOTIFY_TOKENS,
45                             ['PPI'],
46                             False)
47
48        #
49        # To avoid PyLint error
50        #
51        if CommentItemString:
52            pass
53
54        if CommentItemHelpText == None:
55            CommentItemHelpText = ''
56            if Count == len(CommentsList) and CommentItemUsage == CommentItemNotify == DT.ITEM_UNDEFINED:
57                CommentItemHelpText = DT.END_OF_LINE
58        #
59        # For the Last comment Item, set BlockFlag.
60        #
61        if Count == len(CommentsList):
62            if BlockFlag == 1 or BlockFlag == 2:
63                if CommentItemUsage == CommentItemNotify == DT.ITEM_UNDEFINED:
64                    BlockFlag = 4
65                else:
66                    BlockFlag = 3
67            elif BlockFlag == -1:
68                BlockFlag = 4
69
70        #
71        # Comment USAGE and NOTIFY information are "UNDEFINED"
72        #
73        if BlockFlag == -1 or BlockFlag == 1 or BlockFlag == 2:
74            if CommentItemUsage == CommentItemNotify == DT.ITEM_UNDEFINED:
75                if BlockFlag == -1:
76                    BlockFlag = 1
77                elif BlockFlag == 1:
78                    BlockFlag = 2
79            else:
80                if BlockFlag == 1 or BlockFlag == 2:
81                    BlockFlag = 3
82                #
83                # An item have Usage or Notify information and the first time get this information
84                #
85                elif BlockFlag == -1:
86                    BlockFlag = 4
87
88        #
89        # Combine two comment line if they are generic comment
90        #
91        if CommentItemUsage == CommentItemNotify == PreUsage == PreNotify == DT.ITEM_UNDEFINED:
92            CommentItemHelpText = PreHelpText + DT.END_OF_LINE + CommentItemHelpText
93            #
94            # Store this information for next line may still need  combine operation.
95            #
96            PreHelpText = CommentItemHelpText
97
98        if BlockFlag == 4:
99            CommentItemIns = InfPpiItemCommentContent()
100            CommentItemIns.SetUsage(CommentItemUsage)
101            CommentItemIns.SetNotify(CommentItemNotify)
102            CommentItemIns.SetHelpStringItem(CommentItemHelpText)
103            CommentInsList.append(CommentItemIns)
104
105            BlockFlag = -1
106            PreUsage = None
107            PreNotify = None
108            PreHelpText = ''
109
110        elif BlockFlag == 3:
111            #
112            # Add previous help string
113            #
114            CommentItemIns = InfPpiItemCommentContent()
115            CommentItemIns.SetUsage(DT.ITEM_UNDEFINED)
116            CommentItemIns.SetNotify(DT.ITEM_UNDEFINED)
117            if PreHelpText == '' or PreHelpText.endswith(DT.END_OF_LINE):
118                PreHelpText += DT.END_OF_LINE
119            CommentItemIns.SetHelpStringItem(PreHelpText)
120            CommentInsList.append(CommentItemIns)
121            #
122            # Add Current help string
123            #
124            CommentItemIns = InfPpiItemCommentContent()
125            CommentItemIns.SetUsage(CommentItemUsage)
126            CommentItemIns.SetNotify(CommentItemNotify)
127            CommentItemIns.SetHelpStringItem(CommentItemHelpText)
128            CommentInsList.append(CommentItemIns)
129
130            BlockFlag = -1
131            PreUsage = None
132            PreNotify = None
133            PreHelpText = ''
134        else:
135            PreUsage = CommentItemUsage
136            PreNotify = CommentItemNotify
137            PreHelpText = CommentItemHelpText
138
139    InfPpiItemObj.SetCommentList(CommentInsList)
140
141    return InfPpiItemObj
142
143class InfPpiItemCommentContent():
144    def __init__(self):
145        #
146        # ## SOMETIMES_CONSUMES ## HelpString
147        #
148        self.UsageItem = ''
149        #
150        # Help String
151        #
152        self.HelpStringItem = ''
153        self.Notify = ''
154        self.CommentList = []
155
156    def SetUsage(self, UsageItem):
157        self.UsageItem = UsageItem
158    def GetUsage(self):
159        return self.UsageItem
160
161    def SetNotify(self, Notify):
162        if Notify != DT.ITEM_UNDEFINED:
163            self.Notify = 'true'
164    def GetNotify(self):
165        return self.Notify
166
167    def SetHelpStringItem(self, HelpStringItem):
168        self.HelpStringItem = HelpStringItem
169    def GetHelpStringItem(self):
170        return self.HelpStringItem
171
172class InfPpiItem():
173    def __init__(self):
174        self.Name             = ''
175        self.FeatureFlagExp   = ''
176        self.SupArchList      = []
177        self.CommentList      = []
178
179    def SetName(self, Name):
180        self.Name = Name
181    def GetName(self):
182        return self.Name
183
184    def SetSupArchList(self, SupArchList):
185        self.SupArchList = SupArchList
186    def GetSupArchList(self):
187        return self.SupArchList
188
189    def SetCommentList(self, CommentList):
190        self.CommentList = CommentList
191    def GetCommentList(self):
192        return self.CommentList
193
194    def SetFeatureFlagExp(self, FeatureFlagExp):
195        self.FeatureFlagExp = FeatureFlagExp
196    def GetFeatureFlagExp(self):
197        return self.FeatureFlagExp
198##
199#
200#
201#
202class InfPpiObject():
203    def __init__(self):
204        self.Ppis = Sdict()
205        #
206        # Macro defined in this section should be only used in this section.
207        #
208        self.Macros = {}
209
210    def SetPpi(self, PpiList, Arch = None):
211        __SupArchList = []
212        for ArchItem in Arch:
213            #
214            # Validate Arch
215            #
216            if (ArchItem == '' or ArchItem == None):
217                ArchItem = 'COMMON'
218            __SupArchList.append(ArchItem)
219
220        for Item in PpiList:
221            #
222            # Get Comment content of this protocol
223            #
224            CommentsList = None
225            if len(Item) == 3:
226                CommentsList = Item[1]
227            CurrentLineOfItem = Item[2]
228            Item = Item[0]
229            InfPpiItemObj = InfPpiItem()
230            if len(Item) >= 1 and len(Item) <= 2:
231                #
232                # Only CName contained
233                #
234                if not IsValidCVariableName(Item[0]):
235                    Logger.Error("InfParser",
236                                 ToolError.FORMAT_INVALID,
237                                 ST.ERR_INF_PARSER_INVALID_CNAME%(Item[0]),
238                                 File=CurrentLineOfItem[2],
239                                 Line=CurrentLineOfItem[1],
240                                 ExtraData=CurrentLineOfItem[0])
241                if (Item[0] != ''):
242                    InfPpiItemObj.SetName(Item[0])
243                else:
244                    Logger.Error("InfParser",
245                                 ToolError.FORMAT_INVALID,
246                                 ST.ERR_INF_PARSER_CNAME_MISSING,
247                                 File=CurrentLineOfItem[2],
248                                 Line=CurrentLineOfItem[1],
249                                 ExtraData=CurrentLineOfItem[0])
250            #
251            # Have FeatureFlag information
252            #
253            if len(Item) == 2:
254                #
255                # Contained CName and Feature Flag Express
256                # <statements>           ::=  <CName> ["|" <FeatureFlagExpress>]
257                # Item[1] should not be empty
258                #
259                if Item[1].strip() == '':
260                    Logger.Error("InfParser",
261                                 ToolError.FORMAT_INVALID,
262                                 ST.ERR_INF_PARSER_FEATURE_FLAG_EXP_MISSING,
263                                 File=CurrentLineOfItem[2],
264                                 Line=CurrentLineOfItem[1],
265                                 ExtraData=CurrentLineOfItem[0])
266                #
267                # Validate Feature Flag Express for PPI entry
268                # Item[1] contain FFE information
269                #
270                FeatureFlagRtv = IsValidFeatureFlagExp(Item[1].strip())
271                if not FeatureFlagRtv[0]:
272                    Logger.Error("InfParser",
273                                 ToolError.FORMAT_INVALID,
274                                 ST.ERR_INF_PARSER_FEATURE_FLAG_EXP_SYNTAX_INVLID%(FeatureFlagRtv[1]),
275                                 File=CurrentLineOfItem[2],
276                                 Line=CurrentLineOfItem[1],
277                                 ExtraData=CurrentLineOfItem[0])
278                InfPpiItemObj.SetFeatureFlagExp(Item[1])
279            if len(Item) != 1 and len(Item) != 2:
280                #
281                # Invalid format of Ppi statement
282                #
283                Logger.Error("InfParser",
284                             ToolError.FORMAT_INVALID,
285                             ST.ERR_INF_PARSER_GUID_PPI_PROTOCOL_SECTION_CONTENT_ERROR,
286                             File=CurrentLineOfItem[2],
287                             Line=CurrentLineOfItem[1],
288                             ExtraData=CurrentLineOfItem[0])
289
290            #
291            # Get/Set Usage and HelpString for PPI entry
292            #
293            if CommentsList != None and len(CommentsList) != 0:
294                InfPpiItemObj = ParsePpiComment(CommentsList, InfPpiItemObj)
295            else:
296                CommentItemIns = InfPpiItemCommentContent()
297                CommentItemIns.SetUsage(DT.ITEM_UNDEFINED)
298                CommentItemIns.SetNotify(DT.ITEM_UNDEFINED)
299                InfPpiItemObj.SetCommentList([CommentItemIns])
300
301            InfPpiItemObj.SetSupArchList(__SupArchList)
302
303            #
304            # Determine PPI name duplicate. Follow below rule:
305            #
306            # A PPI must not be duplicated within a [Ppis] section.
307            # A PPI may appear in multiple architectural [Ppis]
308            # sections. A PPI listed in an architectural [Ppis]
309            # section must not be listed in the common architectural
310            # [Ppis] section.
311            #
312            # NOTE: This check will not report error now.
313            #
314            for Item in self.Ppis:
315                if Item.GetName() == InfPpiItemObj.GetName():
316                    ItemSupArchList = Item.GetSupArchList()
317                    for ItemArch in ItemSupArchList:
318                        for PpiItemObjArch in __SupArchList:
319                            if ItemArch == PpiItemObjArch:
320                                #
321                                # ST.ERR_INF_PARSER_ITEM_DUPLICATE
322                                #
323                                pass
324                            if ItemArch.upper() == 'COMMON' or PpiItemObjArch.upper() == 'COMMON':
325                                #
326                                # ST.ERR_INF_PARSER_ITEM_DUPLICATE_COMMON
327                                #
328                                pass
329
330            if self.Ppis.has_key((InfPpiItemObj)):
331                PpiList = self.Ppis[InfPpiItemObj]
332                PpiList.append(InfPpiItemObj)
333                self.Ppis[InfPpiItemObj] = PpiList
334            else:
335                PpiList = []
336                PpiList.append(InfPpiItemObj)
337                self.Ppis[InfPpiItemObj] = PpiList
338
339        return True
340
341
342    def GetPpi(self):
343        return self.Ppis