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