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