]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
862974894a6d9c08f923f91c7e80c8e8ba449887
[mirror_edk2.git] / BaseTools / Source / Python / Ecc / MetaFileWorkspace / MetaFileParser.py
1 ## @file
2 # This file is used to parse meta files
3 #
4 # Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
9 #
10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 #
13
14 ##
15 # Import Modules
16 #
17 from __future__ import absolute_import
18 import Common.LongFilePathOs as os
19 import re
20 import time
21 import copy
22
23 import Common.EdkLogger as EdkLogger
24 import Common.GlobalData as GlobalData
25 import Ecc.EccGlobalData as EccGlobalData
26 import Ecc.EccToolError as EccToolError
27
28 from CommonDataClass.DataClass import *
29 from Common.DataType import *
30 from Common.StringUtils import *
31 from Common.Misc import GuidStructureStringToGuidString, CheckPcdDatum, PathClass, AnalyzePcdData
32 from Common.Expression import *
33 from CommonDataClass.Exceptions import *
34
35 from Ecc.MetaFileWorkspace.MetaFileTable import MetaFileStorage
36 from GenFds.FdfParser import FdfParser
37 from Common.LongFilePathSupport import OpenLongFilePath as open
38 from Common.LongFilePathSupport import CodecOpenLongFilePath
39
40 ## A decorator used to parse macro definition
41 def ParseMacro(Parser):
42 def MacroParser(self):
43 Match = GlobalData.gMacroDefPattern.match(self._CurrentLine)
44 if not Match:
45 # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
46 Parser(self)
47 return
48
49 TokenList = GetSplitValueList(self._CurrentLine[Match.end(1):], TAB_EQUAL_SPLIT, 1)
50 # Syntax check
51 if not TokenList[0]:
52 EdkLogger.error('Parser', FORMAT_INVALID, "No macro name given",
53 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
54 if len(TokenList) < 2:
55 TokenList.append('')
56
57 Type = Match.group(1)
58 Name, Value = TokenList
59 # Global macros can be only defined via environment variable
60 if Name in GlobalData.gGlobalDefines:
61 EdkLogger.error('Parser', FORMAT_INVALID, "%s can only be defined via environment variable" % Name,
62 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
63 # Only upper case letters, digit and '_' are allowed
64 if not GlobalData.gMacroNamePattern.match(Name):
65 EdkLogger.error('Parser', FORMAT_INVALID, "The macro name must be in the pattern [A-Z][A-Z0-9_]*",
66 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
67
68 Value = ReplaceMacro(Value, self._Macros)
69 self._ItemType = MODEL_META_DATA_DEFINE
70 # DEFINE defined macros
71 if Type == TAB_DSC_DEFINES_DEFINE:
72 if isinstance(self, DecParser):
73 if MODEL_META_DATA_HEADER in self._SectionType:
74 self._FileLocalMacros[Name] = Value
75 else:
76 for Scope in self._Scope:
77 self._SectionsMacroDict.setdefault((Scope[2], Scope[0], Scope[1]), {})[Name] = Value
78 elif self._SectionType == MODEL_META_DATA_HEADER:
79 self._FileLocalMacros[Name] = Value
80 else:
81 SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
82 if SectionDictKey not in self._SectionsMacroDict:
83 self._SectionsMacroDict[SectionDictKey] = {}
84 SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
85 SectionLocalMacros[Name] = Value
86 # EDK_GLOBAL defined macros
87 elif not isinstance(self, DscParser):
88 EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used in .dsc file",
89 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
90 elif self._SectionType != MODEL_META_DATA_HEADER:
91 EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL can only be used under [Defines] section",
92 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
93 elif (Name in self._FileLocalMacros) and (self._FileLocalMacros[Name] != Value):
94 EdkLogger.error('Parser', FORMAT_INVALID, "EDK_GLOBAL defined a macro with the same name and different value as one defined by 'DEFINE'",
95 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
96
97 self._ValueList = [Type, Name, Value]
98
99 return MacroParser
100
101 ## Base class of parser
102 #
103 # This class is used for derivation purpose. The specific parser for one kind
104 # type file must derive this class and implement some public interfaces.
105 #
106 # @param FilePath The path of platform description file
107 # @param FileType The raw data of DSC file
108 # @param Table Database used to retrieve module/package information
109 # @param Macros Macros used for replacement in file
110 # @param Owner Owner ID (for sub-section parsing)
111 # @param From ID from which the data comes (for !INCLUDE directive)
112 #
113 class MetaFileParser(object):
114 # data type (file content) for specific file type
115 DataType = {}
116
117 # Parser objects used to implement singleton
118 MetaFiles = {}
119
120 ## Factory method
121 #
122 # One file, one parser object. This factory method makes sure that there's
123 # only one object constructed for one meta file.
124 #
125 # @param Class class object of real AutoGen class
126 # (InfParser, DecParser or DscParser)
127 # @param FilePath The path of meta file
128 # @param *args The specific class related parameters
129 # @param **kwargs The specific class related dict parameters
130 #
131 def __new__(Class, FilePath, *args, **kwargs):
132 if FilePath in Class.MetaFiles:
133 return Class.MetaFiles[FilePath]
134 else:
135 ParserObject = super(MetaFileParser, Class).__new__(Class)
136 Class.MetaFiles[FilePath] = ParserObject
137 return ParserObject
138
139 ## Constructor of MetaFileParser
140 #
141 # Initialize object of MetaFileParser
142 #
143 # @param FilePath The path of platform description file
144 # @param FileType The raw data of DSC file
145 # @param Table Database used to retrieve module/package information
146 # @param Macros Macros used for replacement in file
147 # @param Owner Owner ID (for sub-section parsing)
148 # @param From ID from which the data comes (for !INCLUDE directive)
149 #
150 def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
151 self._Table = Table
152 self._RawTable = Table
153 self._FileType = FileType
154 self.MetaFile = FilePath
155 self._Defines = {}
156 self._FileLocalMacros = {}
157 self._SectionsMacroDict = {}
158
159 # for recursive parsing
160 self._Owner = [Owner]
161 self._From = From
162
163 # parsr status for parsing
164 self._ValueList = ['', '', '', '', '']
165 self._Scope = []
166 self._LineIndex = 0
167 self._CurrentLine = ''
168 self._SectionType = MODEL_UNKNOWN
169 self._SectionName = ''
170 self._InSubsection = False
171 self._SubsectionType = MODEL_UNKNOWN
172 self._SubsectionName = ''
173 self._ItemType = MODEL_UNKNOWN
174 self._LastItem = -1
175 self._Enabled = 0
176 self._Finished = False
177 self._PostProcessed = False
178 # Different version of meta-file has different way to parse.
179 self._Version = 0
180 # UNI object and extra UNI object
181 self._UniObj = None
182 self._UniExtraObj = None
183
184 ## Store the parsed data in table
185 def _Store(self, *Args):
186 return self._Table.Insert(*Args)
187
188 ## Virtual method for starting parse
189 def Start(self):
190 raise NotImplementedError
191
192 ## Notify a post-process is needed
193 def DoPostProcess(self):
194 self._PostProcessed = False
195
196 ## Set parsing complete flag in both class and table
197 def _Done(self):
198 self._Finished = True
199 ## Do not set end flag when processing included files
200 if self._From == -1:
201 self._Table.SetEndFlag()
202
203 def _PostProcess(self):
204 self._PostProcessed = True
205
206 ## Get the parse complete flag
207 def _GetFinished(self):
208 return self._Finished
209
210 ## Set the complete flag
211 def _SetFinished(self, Value):
212 self._Finished = Value
213
214 ## Use [] style to query data in table, just for readability
215 #
216 # DataInfo = [data_type, scope1(arch), scope2(platform/moduletype)]
217 #
218 def __getitem__(self, DataInfo):
219 if not isinstance(DataInfo, type(())):
220 DataInfo = (DataInfo,)
221
222 # Parse the file first, if necessary
223 if not self._Finished:
224 if self._RawTable.IsIntegrity():
225 self._Finished = True
226 else:
227 self._Table = self._RawTable
228 self._PostProcessed = False
229 self.Start()
230
231 # No specific ARCH or Platform given, use raw data
232 if self._RawTable and (len(DataInfo) == 1 or DataInfo[1] is None):
233 return self._RawTable.Query(*DataInfo)
234
235 # Do post-process if necessary
236 if not self._PostProcessed:
237 self._PostProcess()
238
239 return self._Table.Query(*DataInfo)
240
241 ## Data parser for the common format in different type of file
242 #
243 # The common format in the meatfile is like
244 #
245 # xxx1 | xxx2 | xxx3
246 #
247 @ParseMacro
248 def _CommonParser(self):
249 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
250 self._ValueList[0:len(TokenList)] = TokenList
251
252 ## Data parser for the format in which there's path
253 #
254 # Only path can have macro used. So we need to replace them before use.
255 #
256 @ParseMacro
257 def _PathParser(self):
258 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
259 self._ValueList[0:len(TokenList)] = TokenList
260 # Don't do macro replacement for dsc file at this point
261 if not isinstance(self, DscParser):
262 Macros = self._Macros
263 self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
264
265 ## Skip unsupported data
266 def _Skip(self):
267 if self._SectionName == TAB_USER_EXTENSIONS.upper() and self._CurrentLine.upper().endswith('.UNI'):
268 if EccGlobalData.gConfig.UniCheckHelpInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
269 ExtraUni = self._CurrentLine.strip()
270 ExtraUniFile = os.path.join(os.path.dirname(self.MetaFile), ExtraUni)
271 IsModuleUni = self.MetaFile.upper().endswith('.INF')
272 self._UniExtraObj = UniParser(ExtraUniFile, IsExtraUni=True, IsModuleUni=IsModuleUni)
273 self._UniExtraObj.Start()
274 else:
275 EdkLogger.warn("Parser", "Unrecognized content", File=self.MetaFile,
276 Line=self._LineIndex + 1, ExtraData=self._CurrentLine);
277 self._ValueList[0:1] = [self._CurrentLine]
278
279 ## Section header parser
280 #
281 # The section header is always in following format:
282 #
283 # [section_name.arch<.platform|module_type>]
284 #
285 def _SectionHeaderParser(self):
286 self._Scope = []
287 self._SectionName = ''
288 ArchList = set()
289 for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
290 if Item == '':
291 continue
292 ItemList = GetSplitValueList(Item, TAB_SPLIT)
293 # different section should not mix in one section
294 if self._SectionName != '' and self._SectionName != ItemList[0].upper():
295 EdkLogger.error('Parser', FORMAT_INVALID, "Different section names in the same section",
296 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
297 self._SectionName = ItemList[0].upper()
298 if self._SectionName in self.DataType:
299 self._SectionType = self.DataType[self._SectionName]
300 else:
301 self._SectionType = MODEL_UNKNOWN
302 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
303 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
304 # S1 is always Arch
305 if len(ItemList) > 1:
306 S1 = ItemList[1].upper()
307 else:
308 S1 = 'COMMON'
309 ArchList.add(S1)
310 # S2 may be Platform or ModuleType
311 if len(ItemList) > 2:
312 S2 = ItemList[2].upper()
313 else:
314 S2 = 'COMMON'
315 self._Scope.append([S1, S2])
316
317 # 'COMMON' must not be used with specific ARCHs at the same section
318 if 'COMMON' in ArchList and len(ArchList) > 1:
319 EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
320 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
321 # If the section information is needed later, it should be stored in database
322 self._ValueList[0] = self._SectionName
323
324 ## [defines] section parser
325 @ParseMacro
326 def _DefineParser(self):
327 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
328 self._ValueList[1:len(TokenList)] = TokenList
329 if not self._ValueList[1]:
330 EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
331 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
332 if not self._ValueList[2]:
333 EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
334 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
335
336 self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
337 Name, Value = self._ValueList[1], self._ValueList[2]
338 # Sometimes, we need to make differences between EDK and EDK2 modules
339 if Name == 'INF_VERSION':
340 try:
341 self._Version = int(Value, 0)
342 except:
343 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid version number",
344 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
345 elif Name == 'MODULE_UNI_FILE':
346 UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
347 if os.path.exists(UniFile):
348 self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=True)
349 self._UniObj.Start()
350 else:
351 EdkLogger.error('Parser', FILE_NOT_FOUND, "Module UNI file %s is missing." % Value,
352 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1,
353 RaiseError=False)
354 elif Name == 'PACKAGE_UNI_FILE':
355 UniFile = os.path.join(os.path.dirname(self.MetaFile), Value)
356 if os.path.exists(UniFile):
357 self._UniObj = UniParser(UniFile, IsExtraUni=False, IsModuleUni=False)
358
359 if isinstance(self, InfParser) and self._Version < 0x00010005:
360 # EDK module allows using defines as macros
361 self._FileLocalMacros[Name] = Value
362 self._Defines[Name] = Value
363
364 ## [BuildOptions] section parser
365 @ParseMacro
366 def _BuildOptionParser(self):
367 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
368 TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
369 if len(TokenList2) == 2:
370 self._ValueList[0] = TokenList2[0] # toolchain family
371 self._ValueList[1] = TokenList2[1] # keys
372 else:
373 self._ValueList[1] = TokenList[0]
374 if len(TokenList) == 2 and not isinstance(self, DscParser): # value
375 self._ValueList[2] = ReplaceMacro(TokenList[1], self._Macros)
376
377 if self._ValueList[1].count('_') != 4:
378 EdkLogger.error(
379 'Parser',
380 FORMAT_INVALID,
381 "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
382 ExtraData=self._CurrentLine,
383 File=self.MetaFile,
384 Line=self._LineIndex+1
385 )
386
387 def _GetMacros(self):
388 Macros = {}
389 Macros.update(self._FileLocalMacros)
390 Macros.update(self._GetApplicableSectionMacro())
391 return Macros
392
393
394 ## Get section Macros that are applicable to current line, which may come from other sections
395 ## that share the same name while scope is wider
396 def _GetApplicableSectionMacro(self):
397 Macros = {}
398 for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", self._Scope[0][1]),
399 (self._Scope[0][0], "COMMON"), (self._Scope[0][0], self._Scope[0][1])]:
400 if (self._SectionType, Scope1, Scope2) in self._SectionsMacroDict:
401 Macros.update(self._SectionsMacroDict[(self._SectionType, Scope1, Scope2)])
402 return Macros
403
404 _SectionParser = {}
405 Finished = property(_GetFinished, _SetFinished)
406 _Macros = property(_GetMacros)
407
408
409 ## INF file parser class
410 #
411 # @param FilePath The path of platform description file
412 # @param FileType The raw data of DSC file
413 # @param Table Database used to retrieve module/package information
414 # @param Macros Macros used for replacement in file
415 #
416 class InfParser(MetaFileParser):
417 # INF file supported data types (one type per section)
418 DataType = {
419 TAB_UNKNOWN.upper() : MODEL_UNKNOWN,
420 TAB_INF_DEFINES.upper() : MODEL_META_DATA_HEADER,
421 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
422 TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
423 TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
424 TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
425 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
426 TAB_PACKAGES.upper() : MODEL_META_DATA_PACKAGE,
427 TAB_NMAKE.upper() : MODEL_META_DATA_NMAKE,
428 TAB_INF_FIXED_PCD.upper() : MODEL_PCD_FIXED_AT_BUILD,
429 TAB_INF_PATCH_PCD.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
430 TAB_INF_FEATURE_PCD.upper() : MODEL_PCD_FEATURE_FLAG,
431 TAB_INF_PCD_EX.upper() : MODEL_PCD_DYNAMIC_EX,
432 TAB_INF_PCD.upper() : MODEL_PCD_DYNAMIC,
433 TAB_SOURCES.upper() : MODEL_EFI_SOURCE_FILE,
434 TAB_GUIDS.upper() : MODEL_EFI_GUID,
435 TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
436 TAB_PPIS.upper() : MODEL_EFI_PPI,
437 TAB_DEPEX.upper() : MODEL_EFI_DEPEX,
438 TAB_BINARIES.upper() : MODEL_EFI_BINARY_FILE,
439 TAB_USER_EXTENSIONS.upper() : MODEL_META_DATA_USER_EXTENSION
440 }
441
442 ## Constructor of InfParser
443 #
444 # Initialize object of InfParser
445 #
446 # @param FilePath The path of module description file
447 # @param FileType The raw data of DSC file
448 # @param Table Database used to retrieve module/package information
449 # @param Macros Macros used for replacement in file
450 #
451 def __init__(self, FilePath, FileType, Table):
452 # prevent re-initialization
453 if hasattr(self, "_Table"):
454 return
455 MetaFileParser.__init__(self, FilePath, FileType, Table)
456 self.TblFile = EccGlobalData.gDb.TblFile
457 self.FileID = -1
458
459 ## Parser starter
460 def Start(self):
461 NmakeLine = ''
462 Content = ''
463 Usage = ''
464 try:
465 Content = open(str(self.MetaFile), 'r').readlines()
466 except:
467 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
468 #
469 # Insert a record for file
470 #
471 Filename = NormPath(self.MetaFile)
472 FileID = self.TblFile.GetFileId(Filename)
473 if FileID:
474 self.FileID = FileID
475 else:
476 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_INF)
477
478 # parse the file line by line
479 IsFindBlockComment = False
480
481 for Index in range(0, len(Content)):
482 if self._SectionType in [MODEL_EFI_GUID,
483 MODEL_EFI_PROTOCOL,
484 MODEL_EFI_PPI,
485 MODEL_PCD_FIXED_AT_BUILD,
486 MODEL_PCD_PATCHABLE_IN_MODULE,
487 MODEL_PCD_FEATURE_FLAG,
488 MODEL_PCD_DYNAMIC_EX,
489 MODEL_PCD_DYNAMIC]:
490 Line = Content[Index].strip()
491 if Line.startswith(TAB_SPECIAL_COMMENT):
492 Usage += ' ' + Line[Line.find(TAB_SPECIAL_COMMENT):]
493 continue
494 elif Line.startswith(TAB_COMMENT_SPLIT):
495 continue
496 elif Line.find(TAB_COMMENT_SPLIT) > 0:
497 Usage += ' ' + Line[Line.find(TAB_COMMENT_SPLIT):]
498 Line = Line[:Line.find(TAB_COMMENT_SPLIT)]
499 else:
500 # skip empty, commented, block commented lines
501 Line = CleanString(Content[Index], AllowCppStyleComment=True)
502 Usage = ''
503 NextLine = ''
504 if Index + 1 < len(Content):
505 NextLine = CleanString(Content[Index + 1])
506 if Line == '':
507 continue
508 if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:
509 IsFindBlockComment = True
510 continue
511 if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:
512 IsFindBlockComment = False
513 continue
514 if IsFindBlockComment:
515 continue
516
517 self._LineIndex = Index
518 self._CurrentLine = Line
519
520 # section header
521 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
522 self._SectionHeaderParser()
523 # Check invalid sections
524 if self._Version < 0x00010005:
525 if self._SectionType in [MODEL_META_DATA_BUILD_OPTION,
526 MODEL_EFI_LIBRARY_CLASS,
527 MODEL_META_DATA_PACKAGE,
528 MODEL_PCD_FIXED_AT_BUILD,
529 MODEL_PCD_PATCHABLE_IN_MODULE,
530 MODEL_PCD_FEATURE_FLAG,
531 MODEL_PCD_DYNAMIC_EX,
532 MODEL_PCD_DYNAMIC,
533 MODEL_EFI_GUID,
534 MODEL_EFI_PROTOCOL,
535 MODEL_EFI_PPI,
536 MODEL_META_DATA_USER_EXTENSION]:
537 EdkLogger.error('Parser', FORMAT_INVALID,
538 "Section [%s] is not allowed in inf file without version" % (self._SectionName),
539 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
540 elif self._SectionType in [MODEL_EFI_INCLUDE,
541 MODEL_EFI_LIBRARY_INSTANCE,
542 MODEL_META_DATA_NMAKE]:
543 EdkLogger.error('Parser', FORMAT_INVALID,
544 "Section [%s] is not allowed in inf file with version 0x%08x" % (self._SectionName, self._Version),
545 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
546 continue
547 # merge two lines specified by '\' in section NMAKE
548 elif self._SectionType == MODEL_META_DATA_NMAKE:
549 if Line[-1] == '\\':
550 if NextLine == '':
551 self._CurrentLine = NmakeLine + Line[0:-1]
552 NmakeLine = ''
553 else:
554 if NextLine[0] == TAB_SECTION_START and NextLine[-1] == TAB_SECTION_END:
555 self._CurrentLine = NmakeLine + Line[0:-1]
556 NmakeLine = ''
557 else:
558 NmakeLine = NmakeLine + ' ' + Line[0:-1]
559 continue
560 else:
561 self._CurrentLine = NmakeLine + Line
562 NmakeLine = ''
563
564 # section content
565 self._ValueList = ['', '', '']
566 # parse current line, result will be put in self._ValueList
567 self._SectionParser[self._SectionType](self)
568 if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
569 self._ItemType = -1
570 continue
571 #
572 # Model, Value1, Value2, Value3, Arch, Platform, BelongsToItem=-1,
573 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
574 #
575 self._ValueList[0] = self._ValueList[0].replace('/', '\\')
576 Usage = Usage.strip()
577 for Arch, Platform in self._Scope:
578 self._Store(self._SectionType,
579 self._ValueList[0],
580 self._ValueList[1],
581 self._ValueList[2],
582 Arch,
583 Platform,
584 self._Owner[-1],
585 self.FileID,
586 self._LineIndex+1,
587 -1,
588 self._LineIndex+1,
589 -1,
590 0,
591 Usage
592 )
593 Usage = ''
594 if IsFindBlockComment:
595 EdkLogger.error("Parser", FORMAT_INVALID, "Open block comments (starting with /*) are expected to end with */",
596 File=self.MetaFile)
597 self._Done()
598
599 ## Data parser for the format in which there's path
600 #
601 # Only path can have macro used. So we need to replace them before use.
602 #
603 def _IncludeParser(self):
604 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
605 self._ValueList[0:len(TokenList)] = TokenList
606 Macros = self._Macros
607 if Macros:
608 for Index in range(0, len(self._ValueList)):
609 Value = self._ValueList[Index]
610 if not Value:
611 continue
612
613 self._ValueList[Index] = ReplaceMacro(Value, Macros)
614
615 ## Parse [Sources] section
616 #
617 # Only path can have macro used. So we need to replace them before use.
618 #
619 @ParseMacro
620 def _SourceFileParser(self):
621 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
622 self._ValueList[0:len(TokenList)] = TokenList
623 Macros = self._Macros
624 # For Acpi tables, remove macro like ' TABLE_NAME=Sata1'
625 if 'COMPONENT_TYPE' in Macros:
626 if self._Defines['COMPONENT_TYPE'].upper() == 'ACPITABLE':
627 self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0]
628 if self._Defines['BASE_NAME'] == 'Microcode':
629 pass
630 self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
631
632 ## Parse [Binaries] section
633 #
634 # Only path can have macro used. So we need to replace them before use.
635 #
636 @ParseMacro
637 def _BinaryFileParser(self):
638 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2)
639 if len(TokenList) < 2:
640 EdkLogger.error('Parser', FORMAT_INVALID, "No file type or path specified",
641 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
642 File=self.MetaFile, Line=self._LineIndex+1)
643 if not TokenList[0]:
644 EdkLogger.error('Parser', FORMAT_INVALID, "No file type specified",
645 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
646 File=self.MetaFile, Line=self._LineIndex+1)
647 if not TokenList[1]:
648 EdkLogger.error('Parser', FORMAT_INVALID, "No file path specified",
649 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
650 File=self.MetaFile, Line=self._LineIndex+1)
651 self._ValueList[0:len(TokenList)] = TokenList
652 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
653
654 ## [nmake] section parser (Edk.x style only)
655 def _NmakeParser(self):
656 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
657 self._ValueList[0:len(TokenList)] = TokenList
658 # remove macros
659 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
660 # remove self-reference in macro setting
661 #self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})
662
663 ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
664 @ParseMacro
665 def _PcdParser(self):
666 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
667 ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT)
668 if len(ValueList) != 2:
669 EdkLogger.error('Parser', FORMAT_INVALID, "Illegal token space GUID and PCD name format",
670 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
671 File=self.MetaFile, Line=self._LineIndex+1)
672 self._ValueList[0:1] = ValueList
673 if len(TokenList) > 1:
674 self._ValueList[2] = TokenList[1]
675 if self._ValueList[0] == '' or self._ValueList[1] == '':
676 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
677 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
678 File=self.MetaFile, Line=self._LineIndex+1)
679
680 # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
681 if self._ValueList[2] != '':
682 InfPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
683 if InfPcdValueList[0] in ['True', 'true', 'TRUE']:
684 self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '1', 1);
685 elif InfPcdValueList[0] in ['False', 'false', 'FALSE']:
686 self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '0', 1);
687
688 ## [depex] section parser
689 @ParseMacro
690 def _DepexParser(self):
691 self._ValueList[0:1] = [self._CurrentLine]
692
693 _SectionParser = {
694 MODEL_UNKNOWN : MetaFileParser._Skip,
695 MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
696 MODEL_META_DATA_BUILD_OPTION : MetaFileParser._BuildOptionParser,
697 MODEL_EFI_INCLUDE : _IncludeParser, # for Edk.x modules
698 MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._CommonParser, # for Edk.x modules
699 MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
700 MODEL_META_DATA_PACKAGE : MetaFileParser._PathParser,
701 MODEL_META_DATA_NMAKE : _NmakeParser, # for Edk.x modules
702 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
703 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
704 MODEL_PCD_FEATURE_FLAG : _PcdParser,
705 MODEL_PCD_DYNAMIC_EX : _PcdParser,
706 MODEL_PCD_DYNAMIC : _PcdParser,
707 MODEL_EFI_SOURCE_FILE : _SourceFileParser,
708 MODEL_EFI_GUID : MetaFileParser._CommonParser,
709 MODEL_EFI_PROTOCOL : MetaFileParser._CommonParser,
710 MODEL_EFI_PPI : MetaFileParser._CommonParser,
711 MODEL_EFI_DEPEX : _DepexParser,
712 MODEL_EFI_BINARY_FILE : _BinaryFileParser,
713 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
714 }
715
716 ## DSC file parser class
717 #
718 # @param FilePath The path of platform description file
719 # @param FileType The raw data of DSC file
720 # @param Table Database used to retrieve module/package information
721 # @param Macros Macros used for replacement in file
722 # @param Owner Owner ID (for sub-section parsing)
723 # @param From ID from which the data comes (for !INCLUDE directive)
724 #
725 class DscParser(MetaFileParser):
726 # DSC file supported data types (one type per section)
727 DataType = {
728 TAB_SKUIDS.upper() : MODEL_EFI_SKU_ID,
729 TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
730 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
731 TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
732 TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
733 TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
734 TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
735 TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_DEFAULT,
736 TAB_PCDS_DYNAMIC_HII_NULL.upper() : MODEL_PCD_DYNAMIC_HII,
737 TAB_PCDS_DYNAMIC_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_VPD,
738 TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_EX_DEFAULT,
739 TAB_PCDS_DYNAMIC_EX_HII_NULL.upper() : MODEL_PCD_DYNAMIC_EX_HII,
740 TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_EX_VPD,
741 TAB_COMPONENTS.upper() : MODEL_META_DATA_COMPONENT,
742 TAB_COMPONENTS_SOURCE_OVERRIDE_PATH.upper() : MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH,
743 TAB_DSC_DEFINES.upper() : MODEL_META_DATA_HEADER,
744 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
745 TAB_DSC_DEFINES_EDKGLOBAL : MODEL_META_DATA_GLOBAL_DEFINE,
746 TAB_INCLUDE.upper() : MODEL_META_DATA_INCLUDE,
747 TAB_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
748 TAB_IF_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
749 TAB_IF_N_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,
750 TAB_ELSE_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,
751 TAB_ELSE.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
752 TAB_END_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,
753 TAB_ERROR.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR,
754 }
755
756 # Valid names in define section
757 DefineKeywords = [
758 "DSC_SPECIFICATION",
759 "PLATFORM_NAME",
760 "PLATFORM_GUID",
761 "PLATFORM_VERSION",
762 "SKUID_IDENTIFIER",
763 "PCD_INFO_GENERATION",
764 "SUPPORTED_ARCHITECTURES",
765 "BUILD_TARGETS",
766 "OUTPUT_DIRECTORY",
767 "FLASH_DEFINITION",
768 "BUILD_NUMBER",
769 "RFC_LANGUAGES",
770 "ISO_LANGUAGES",
771 "TIME_STAMP_FILE",
772 "VPD_TOOL_GUID",
773 "FIX_LOAD_TOP_MEMORY_ADDRESS"
774 ]
775
776 SubSectionDefineKeywords = [
777 "FILE_GUID"
778 ]
779
780 SymbolPattern = ValueExpression.SymbolPattern
781
782 ## Constructor of DscParser
783 #
784 # Initialize object of DscParser
785 #
786 # @param FilePath The path of platform description file
787 # @param FileType The raw data of DSC file
788 # @param Table Database used to retrieve module/package information
789 # @param Macros Macros used for replacement in file
790 # @param Owner Owner ID (for sub-section parsing)
791 # @param From ID from which the data comes (for !INCLUDE directive)
792 #
793 def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
794 # prevent re-initialization
795 if hasattr(self, "_Table"):
796 return
797 MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From)
798 self._Version = 0x00010005 # Only EDK2 dsc file is supported
799 # to store conditional directive evaluation result
800 self._DirectiveStack = []
801 self._DirectiveEvalStack = []
802 self._Enabled = 1
803
804 # Final valid replacable symbols
805 self._Symbols = {}
806 #
807 # Map the ID between the original table and new table to track
808 # the owner item
809 #
810 self._IdMapping = {-1:-1}
811
812 self.TblFile = EccGlobalData.gDb.TblFile
813 self.FileID = -1
814
815 ## Parser starter
816 def Start(self):
817 Content = ''
818 try:
819 Content = open(str(self.MetaFile.Path), 'r').readlines()
820 except:
821 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
822 #
823 # Insert a record for file
824 #
825 Filename = NormPath(self.MetaFile.Path)
826 FileID = self.TblFile.GetFileId(Filename)
827 if FileID:
828 self.FileID = FileID
829 else:
830 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DSC)
831
832
833 for Index in range(0, len(Content)):
834 Line = CleanString(Content[Index])
835 # skip empty line
836 if Line == '':
837 continue
838
839 self._CurrentLine = Line
840 self._LineIndex = Index
841 if self._InSubsection and self._Owner[-1] == -1:
842 self._Owner.append(self._LastItem)
843
844 # section header
845 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
846 self._SectionType = MODEL_META_DATA_SECTION_HEADER
847 # subsection ending
848 elif Line[0] == '}' and self._InSubsection:
849 self._InSubsection = False
850 self._SubsectionType = MODEL_UNKNOWN
851 self._SubsectionName = ''
852 self._Owner[-1] = -1
853 continue
854 # subsection header
855 elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
856 self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER
857 # directive line
858 elif Line[0] == '!':
859 self._DirectiveParser()
860 continue
861
862 if self._InSubsection:
863 SectionType = self._SubsectionType
864 else:
865 SectionType = self._SectionType
866 self._ItemType = SectionType
867
868 self._ValueList = ['', '', '']
869 self._SectionParser[SectionType](self)
870 if self._ValueList is None:
871 continue
872 #
873 # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
874 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
875 #
876 for Arch, ModuleType in self._Scope:
877 self._LastItem = self._Store(
878 self._ItemType,
879 self._ValueList[0],
880 self._ValueList[1],
881 self._ValueList[2],
882 Arch,
883 ModuleType,
884 self._Owner[-1],
885 self.FileID,
886 self._From,
887 self._LineIndex+1,
888 -1,
889 self._LineIndex+1,
890 -1,
891 self._Enabled
892 )
893
894 if self._DirectiveStack:
895 Type, Line, Text = self._DirectiveStack[-1]
896 EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found",
897 ExtraData=Text, File=self.MetaFile, Line=Line)
898 self._Done()
899
900 ## <subsection_header> parser
901 def _SubsectionHeaderParser(self):
902 self._SubsectionName = self._CurrentLine[1:-1].upper()
903 if self._SubsectionName in self.DataType:
904 self._SubsectionType = self.DataType[self._SubsectionName]
905 else:
906 self._SubsectionType = MODEL_UNKNOWN
907 EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
908 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
909 self._ValueList[0] = self._SubsectionName
910
911 ## Directive statement parser
912 def _DirectiveParser(self):
913 self._ValueList = ['', '', '']
914 TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
915 self._ValueList[0:len(TokenList)] = TokenList
916
917 # Syntax check
918 DirectiveName = self._ValueList[0].upper()
919 if DirectiveName not in self.DataType:
920 EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
921 File=self.MetaFile, Line=self._LineIndex+1)
922 if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
923 EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
924 File=self.MetaFile, Line=self._LineIndex+1,
925 ExtraData=self._CurrentLine)
926
927 ItemType = self.DataType[DirectiveName]
928 if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
929 # Remove all directives between !if and !endif, including themselves
930 while self._DirectiveStack:
931 # Remove any !else or !elseif
932 DirectiveInfo = self._DirectiveStack.pop()
933 if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
934 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
935 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
936 break
937 else:
938 EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'",
939 File=self.MetaFile, Line=self._LineIndex+1,
940 ExtraData=self._CurrentLine)
941 elif ItemType != MODEL_META_DATA_INCLUDE:
942 # Break if there's a !else is followed by a !elseif
943 if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \
944 self._DirectiveStack and \
945 self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
946 EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'",
947 File=self.MetaFile, Line=self._LineIndex+1,
948 ExtraData=self._CurrentLine)
949 self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine))
950 elif self._From > 0:
951 EdkLogger.error('Parser', FORMAT_INVALID,
952 "No '!include' allowed in included file",
953 ExtraData=self._CurrentLine, File=self.MetaFile,
954 Line=self._LineIndex+1)
955
956 #
957 # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
958 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
959 #
960 self._LastItem = self._Store(
961 ItemType,
962 self._ValueList[0],
963 self._ValueList[1],
964 self._ValueList[2],
965 'COMMON',
966 'COMMON',
967 self._Owner[-1],
968 self.FileID,
969 self._From,
970 self._LineIndex+1,
971 -1,
972 self._LineIndex+1,
973 -1,
974 0
975 )
976
977 ## [defines] section parser
978 @ParseMacro
979 def _DefineParser(self):
980 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
981 self._ValueList[1:len(TokenList)] = TokenList
982
983 # Syntax check
984 if not self._ValueList[1]:
985 EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
986 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
987 if not self._ValueList[2]:
988 EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
989 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
990 if (not self._ValueList[1] in self.DefineKeywords and
991 (self._InSubsection and self._ValueList[1] not in self.SubSectionDefineKeywords)):
992 EdkLogger.error('Parser', FORMAT_INVALID,
993 "Unknown keyword found: %s. "
994 "If this is a macro you must "
995 "add it as a DEFINE in the DSC" % self._ValueList[1],
996 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
997 self._Defines[self._ValueList[1]] = self._ValueList[2]
998 self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()]
999
1000 @ParseMacro
1001 def _SkuIdParser(self):
1002 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1003 if len(TokenList) != 2:
1004 EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '<Integer>|<UiName>'",
1005 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1006 self._ValueList[0:len(TokenList)] = TokenList
1007
1008 ## Parse Edk style of library modules
1009 def _LibraryInstanceParser(self):
1010 self._ValueList[0] = self._CurrentLine
1011
1012 ## PCD sections parser
1013 #
1014 # [PcdsFixedAtBuild]
1015 # [PcdsPatchableInModule]
1016 # [PcdsFeatureFlag]
1017 # [PcdsDynamicEx
1018 # [PcdsDynamicExDefault]
1019 # [PcdsDynamicExVpd]
1020 # [PcdsDynamicExHii]
1021 # [PcdsDynamic]
1022 # [PcdsDynamicDefault]
1023 # [PcdsDynamicVpd]
1024 # [PcdsDynamicHii]
1025 #
1026 @ParseMacro
1027 def _PcdParser(self):
1028 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1029 self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1030 if len(TokenList) == 2:
1031 self._ValueList[2] = TokenList[1]
1032 if self._ValueList[0] == '' or self._ValueList[1] == '':
1033 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1034 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1035 File=self.MetaFile, Line=self._LineIndex+1)
1036 if self._ValueList[2] == '':
1037 EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
1038 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1039 File=self.MetaFile, Line=self._LineIndex+1)
1040 # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
1041 DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
1042 if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
1043 self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
1044 elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
1045 self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
1046
1047 ## [components] section parser
1048 @ParseMacro
1049 def _ComponentParser(self):
1050 if self._CurrentLine[-1] == '{':
1051 self._ValueList[0] = self._CurrentLine[0:-1].strip()
1052 self._InSubsection = True
1053 else:
1054 self._ValueList[0] = self._CurrentLine
1055
1056 ## [LibraryClasses] section
1057 @ParseMacro
1058 def _LibraryClassParser(self):
1059 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1060 if len(TokenList) < 2:
1061 EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
1062 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1063 File=self.MetaFile, Line=self._LineIndex+1)
1064 if TokenList[0] == '':
1065 EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
1066 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1067 File=self.MetaFile, Line=self._LineIndex+1)
1068 if TokenList[1] == '':
1069 EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
1070 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1071 File=self.MetaFile, Line=self._LineIndex+1)
1072
1073 self._ValueList[0:len(TokenList)] = TokenList
1074
1075 def _CompponentSourceOverridePathParser(self):
1076 self._ValueList[0] = self._CurrentLine
1077
1078 ## [BuildOptions] section parser
1079 @ParseMacro
1080 def _BuildOptionParser(self):
1081 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1082 TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
1083 if len(TokenList2) == 2:
1084 self._ValueList[0] = TokenList2[0] # toolchain family
1085 self._ValueList[1] = TokenList2[1] # keys
1086 else:
1087 self._ValueList[1] = TokenList[0]
1088 if len(TokenList) == 2: # value
1089 self._ValueList[2] = TokenList[1]
1090
1091 if self._ValueList[1].count('_') != 4:
1092 EdkLogger.error(
1093 'Parser',
1094 FORMAT_INVALID,
1095 "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
1096 ExtraData=self._CurrentLine,
1097 File=self.MetaFile,
1098 Line=self._LineIndex+1
1099 )
1100
1101 ## Override parent's method since we'll do all macro replacements in parser
1102 def _GetMacros(self):
1103 Macros = dict( [('ARCH', 'IA32'), ('FAMILY', TAB_COMPILER_MSFT), ('TOOL_CHAIN_TAG', 'VS2008x86'), ('TARGET', 'DEBUG')])
1104 Macros.update(self._FileLocalMacros)
1105 Macros.update(self._GetApplicableSectionMacro())
1106 Macros.update(GlobalData.gEdkGlobal)
1107 Macros.update(GlobalData.gPlatformDefines)
1108 Macros.update(GlobalData.gCommandLineDefines)
1109 # PCD cannot be referenced in macro definition
1110 if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]:
1111 Macros.update(self._Symbols)
1112 return Macros
1113
1114 def _PostProcess(self):
1115 Processer = {
1116 MODEL_META_DATA_SECTION_HEADER : self.__ProcessSectionHeader,
1117 MODEL_META_DATA_SUBSECTION_HEADER : self.__ProcessSubsectionHeader,
1118 MODEL_META_DATA_HEADER : self.__ProcessDefine,
1119 MODEL_META_DATA_DEFINE : self.__ProcessDefine,
1120 MODEL_META_DATA_GLOBAL_DEFINE : self.__ProcessDefine,
1121 MODEL_META_DATA_INCLUDE : self.__ProcessDirective,
1122 MODEL_META_DATA_CONDITIONAL_STATEMENT_IF : self.__ProcessDirective,
1123 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE : self.__ProcessDirective,
1124 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF : self.__ProcessDirective,
1125 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF : self.__ProcessDirective,
1126 MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF : self.__ProcessDirective,
1127 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF : self.__ProcessDirective,
1128 MODEL_EFI_SKU_ID : self.__ProcessSkuId,
1129 MODEL_EFI_LIBRARY_INSTANCE : self.__ProcessLibraryInstance,
1130 MODEL_EFI_LIBRARY_CLASS : self.__ProcessLibraryClass,
1131 MODEL_PCD_FIXED_AT_BUILD : self.__ProcessPcd,
1132 MODEL_PCD_PATCHABLE_IN_MODULE : self.__ProcessPcd,
1133 MODEL_PCD_FEATURE_FLAG : self.__ProcessPcd,
1134 MODEL_PCD_DYNAMIC_DEFAULT : self.__ProcessPcd,
1135 MODEL_PCD_DYNAMIC_HII : self.__ProcessPcd,
1136 MODEL_PCD_DYNAMIC_VPD : self.__ProcessPcd,
1137 MODEL_PCD_DYNAMIC_EX_DEFAULT : self.__ProcessPcd,
1138 MODEL_PCD_DYNAMIC_EX_HII : self.__ProcessPcd,
1139 MODEL_PCD_DYNAMIC_EX_VPD : self.__ProcessPcd,
1140 MODEL_META_DATA_COMPONENT : self.__ProcessComponent,
1141 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : self.__ProcessSourceOverridePath,
1142 MODEL_META_DATA_BUILD_OPTION : self.__ProcessBuildOption,
1143 MODEL_UNKNOWN : self._Skip,
1144 MODEL_META_DATA_USER_EXTENSION : self._Skip,
1145 MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR : self._Skip,
1146 }
1147
1148 self._RawTable = self._Table
1149 self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True)
1150 self._DirectiveStack = []
1151 self._DirectiveEvalStack = []
1152 self._FileWithError = self.MetaFile
1153 self._FileLocalMacros = {}
1154 self._SectionsMacroDict = {}
1155 GlobalData.gPlatformDefines = {}
1156
1157 # Get all macro and PCD which has straitforward value
1158 self.__RetrievePcdValue()
1159 self._Content = self._RawTable.GetAll()
1160 self._ContentIndex = 0
1161 while self._ContentIndex < len(self._Content) :
1162 Id, self._ItemType, V1, V2, V3, S1, S2, Owner, BelongsToFile, self._From, \
1163 LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex]
1164
1165 if self._From < 0:
1166 self._FileWithError = self.MetaFile
1167
1168 self._ContentIndex += 1
1169
1170 self._Scope = [[S1, S2]]
1171 self._LineIndex = LineStart - 1
1172 self._ValueList = [V1, V2, V3]
1173
1174 try:
1175 Processer[self._ItemType]()
1176 except EvaluationException as Excpt:
1177 #
1178 # Only catch expression evaluation error here. We need to report
1179 # the precise number of line on which the error occurred
1180 #
1181 pass
1182 # EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
1183 # File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1184 # Line=self._LineIndex+1)
1185 except MacroException as Excpt:
1186 EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
1187 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1188 Line=self._LineIndex+1)
1189
1190 if self._ValueList is None:
1191 continue
1192
1193 NewOwner = self._IdMapping.get(Owner, -1)
1194 self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack))
1195 self._LastItem = self._Store(
1196 self._ItemType,
1197 self._ValueList[0],
1198 self._ValueList[1],
1199 self._ValueList[2],
1200 S1,
1201 S2,
1202 NewOwner,
1203 BelongsToFile,
1204 self._From,
1205 self._LineIndex+1,
1206 -1,
1207 self._LineIndex+1,
1208 -1,
1209 self._Enabled
1210 )
1211 self._IdMapping[Id] = self._LastItem
1212
1213 RecordList = self._Table.GetAll()
1214
1215 self._RawTable.Drop()
1216 self._Table.Drop()
1217 for Record in RecordList:
1218 EccGlobalData.gDb.TblDsc.Insert(Record[1], Record[2], Record[3], Record[4], Record[5], Record[6], Record[7], Record[8], Record[9], Record[10], Record[11], Record[12], Record[13], Record[14])
1219 GlobalData.gPlatformDefines.update(self._FileLocalMacros)
1220 self._PostProcessed = True
1221 self._Content = None
1222
1223 def __ProcessSectionHeader(self):
1224 self._SectionName = self._ValueList[0]
1225 if self._SectionName in self.DataType:
1226 self._SectionType = self.DataType[self._SectionName]
1227 else:
1228 self._SectionType = MODEL_UNKNOWN
1229
1230 def __ProcessSubsectionHeader(self):
1231 self._SubsectionName = self._ValueList[0]
1232 if self._SubsectionName in self.DataType:
1233 self._SubsectionType = self.DataType[self._SubsectionName]
1234 else:
1235 self._SubsectionType = MODEL_UNKNOWN
1236
1237 def __RetrievePcdValue(self):
1238 Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0)
1239 for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
1240 Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1241 # Only use PCD whose value is straitforward (no macro and PCD)
1242 if self.SymbolPattern.findall(Value):
1243 continue
1244 Name = TokenSpaceGuid + '.' + PcdName
1245 # Don't use PCD with different values.
1246 if Name in self._Symbols and self._Symbols[Name] != Value:
1247 self._Symbols.pop(Name)
1248 continue
1249 self._Symbols[Name] = Value
1250
1251 Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0)
1252 for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
1253 Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1254 # Only use PCD whose value is straitforward (no macro and PCD)
1255 if self.SymbolPattern.findall(Value):
1256 continue
1257 Name = TokenSpaceGuid+'.'+PcdName
1258 # Don't use PCD with different values.
1259 if Name in self._Symbols and self._Symbols[Name] != Value:
1260 self._Symbols.pop(Name)
1261 continue
1262 self._Symbols[Name] = Value
1263
1264 def __ProcessDefine(self):
1265 if not self._Enabled:
1266 return
1267
1268 Type, Name, Value = self._ValueList
1269 Value = ReplaceMacro(Value, self._Macros, False)
1270 if self._ItemType == MODEL_META_DATA_DEFINE:
1271 if self._SectionType == MODEL_META_DATA_HEADER:
1272 self._FileLocalMacros[Name] = Value
1273 else:
1274 SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
1275 if SectionDictKey not in self._SectionsMacroDict:
1276 self._SectionsMacroDict[SectionDictKey] = {}
1277 SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
1278 SectionLocalMacros[Name] = Value
1279 elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
1280 GlobalData.gEdkGlobal[Name] = Value
1281
1282 #
1283 # Keyword in [Defines] section can be used as Macros
1284 #
1285 if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER):
1286 self._FileLocalMacros[Name] = Value
1287
1288 self._ValueList = [Type, Name, Value]
1289
1290 def __ProcessDirective(self):
1291 Result = None
1292 if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1293 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]:
1294 Macros = self._Macros
1295 Macros.update(GlobalData.gGlobalDefines)
1296 try:
1297 Result = ValueExpression(self._ValueList[1], Macros)()
1298 except SymbolNotFound as Exc:
1299 EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1300 Result = False
1301 except WrnExpression as Excpt:
1302 #
1303 # Catch expression evaluation warning here. We need to report
1304 # the precise number of line and return the evaluation result
1305 #
1306 EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt),
1307 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1308 Line=self._LineIndex+1)
1309 Result = Excpt.result
1310 except BadExpression as Exc:
1311 EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1312 Result = False
1313
1314 if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1315 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1316 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1317 self._DirectiveStack.append(self._ItemType)
1318 if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF:
1319 Result = bool(Result)
1320 else:
1321 Macro = self._ValueList[1]
1322 Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro
1323 Result = Macro in self._Macros
1324 if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF:
1325 Result = not Result
1326 self._DirectiveEvalStack.append(Result)
1327 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF:
1328 self._DirectiveStack.append(self._ItemType)
1329 self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1330 self._DirectiveEvalStack.append(bool(Result))
1331 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
1332 self._DirectiveStack[-1] = self._ItemType
1333 self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1334 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
1335 # Back to the nearest !if/!ifdef/!ifndef
1336 while self._DirectiveStack:
1337 self._DirectiveEvalStack.pop()
1338 Directive = self._DirectiveStack.pop()
1339 if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1340 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1341 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
1342 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1343 break
1344 elif self._ItemType == MODEL_META_DATA_INCLUDE:
1345 # The included file must be relative to workspace or same directory as DSC file
1346 __IncludeMacros = {}
1347 #
1348 # Allow using system environment variables in path after !include
1349 #
1350 __IncludeMacros['WORKSPACE'] = GlobalData.gGlobalDefines['WORKSPACE']
1351
1352 #
1353 # Allow using MACROs comes from [Defines] section to keep compatible.
1354 #
1355 __IncludeMacros.update(self._Macros)
1356
1357 IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], __IncludeMacros, RaiseError=True))
1358 #
1359 # First search the include file under the same directory as DSC file
1360 #
1361 IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir)
1362 ErrorCode, ErrorInfo1 = IncludedFile1.Validate()
1363 if ErrorCode != 0:
1364 #
1365 # Also search file under the WORKSPACE directory
1366 #
1367 IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace)
1368 ErrorCode, ErrorInfo2 = IncludedFile1.Validate()
1369 if ErrorCode != 0:
1370 EdkLogger.error('parser', ErrorCode, File=self._FileWithError,
1371 Line=self._LineIndex+1, ExtraData=ErrorInfo1 + "\n"+ ErrorInfo2)
1372
1373 self._FileWithError = IncludedFile1
1374
1375 IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile1, MODEL_FILE_DSC, True)
1376 Owner = self._Content[self._ContentIndex-1][0]
1377 Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,
1378 Owner=Owner, From=Owner)
1379
1380 # set the parser status with current status
1381 Parser._SectionName = self._SectionName
1382 Parser._SectionType = self._SectionType
1383 Parser._Scope = self._Scope
1384 Parser._Enabled = self._Enabled
1385 # Parse the included file
1386 Parser.Start()
1387
1388 # update current status with sub-parser's status
1389 self._SectionName = Parser._SectionName
1390 self._SectionType = Parser._SectionType
1391 self._Scope = Parser._Scope
1392 self._Enabled = Parser._Enabled
1393
1394 # Insert all records in the table for the included file into dsc file table
1395 Records = IncludedFileTable.GetAll()
1396 if Records:
1397 self._Content[self._ContentIndex:self._ContentIndex] = Records
1398 self._Content.pop(self._ContentIndex-1)
1399 self._ValueList = None
1400 self._ContentIndex -= 1
1401
1402 def __ProcessSkuId(self):
1403 self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True)
1404 for Value in self._ValueList]
1405
1406 def __ProcessLibraryInstance(self):
1407 self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
1408
1409 def __ProcessLibraryClass(self):
1410 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
1411
1412 def __ProcessPcd(self):
1413 ValueList = GetSplitValueList(self._ValueList[2])
1414 #
1415 # PCD value can be an expression
1416 #
1417 if len(ValueList) > 1 and ValueList[1] == TAB_VOID:
1418 PcdValue = ValueList[0]
1419 try:
1420 ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
1421 except WrnExpression as Value:
1422 ValueList[0] = Value.result
1423 else:
1424 PcdValue = ValueList[-1]
1425 try:
1426 ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
1427 except WrnExpression as Value:
1428 ValueList[-1] = Value.result
1429
1430 if ValueList[-1] == 'True':
1431 ValueList[-1] = '1'
1432 if ValueList[-1] == 'False':
1433 ValueList[-1] = '0'
1434
1435 self._ValueList[2] = '|'.join(ValueList)
1436
1437 def __ProcessComponent(self):
1438 self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1439
1440 def __ProcessSourceOverridePath(self):
1441 self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1442
1443 def __ProcessBuildOption(self):
1444 self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False)
1445 for Value in self._ValueList]
1446
1447 _SectionParser = {
1448 MODEL_META_DATA_HEADER : _DefineParser,
1449 MODEL_EFI_SKU_ID : _SkuIdParser,
1450 MODEL_EFI_LIBRARY_INSTANCE : _LibraryInstanceParser,
1451 MODEL_EFI_LIBRARY_CLASS : _LibraryClassParser,
1452 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
1453 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
1454 MODEL_PCD_FEATURE_FLAG : _PcdParser,
1455 MODEL_PCD_DYNAMIC_DEFAULT : _PcdParser,
1456 MODEL_PCD_DYNAMIC_HII : _PcdParser,
1457 MODEL_PCD_DYNAMIC_VPD : _PcdParser,
1458 MODEL_PCD_DYNAMIC_EX_DEFAULT : _PcdParser,
1459 MODEL_PCD_DYNAMIC_EX_HII : _PcdParser,
1460 MODEL_PCD_DYNAMIC_EX_VPD : _PcdParser,
1461 MODEL_META_DATA_COMPONENT : _ComponentParser,
1462 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : _CompponentSourceOverridePathParser,
1463 MODEL_META_DATA_BUILD_OPTION : _BuildOptionParser,
1464 MODEL_UNKNOWN : MetaFileParser._Skip,
1465 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
1466 MODEL_META_DATA_SECTION_HEADER : MetaFileParser._SectionHeaderParser,
1467 MODEL_META_DATA_SUBSECTION_HEADER : _SubsectionHeaderParser,
1468 }
1469
1470 _Macros = property(_GetMacros)
1471
1472 ## DEC file parser class
1473 #
1474 # @param FilePath The path of platform description file
1475 # @param FileType The raw data of DSC file
1476 # @param Table Database used to retrieve module/package information
1477 # @param Macros Macros used for replacement in file
1478 #
1479 class DecParser(MetaFileParser):
1480 # DEC file supported data types (one type per section)
1481 DataType = {
1482 TAB_DEC_DEFINES.upper() : MODEL_META_DATA_HEADER,
1483 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
1484 TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
1485 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
1486 TAB_GUIDS.upper() : MODEL_EFI_GUID,
1487 TAB_PPIS.upper() : MODEL_EFI_PPI,
1488 TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
1489 TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
1490 TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
1491 TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
1492 TAB_PCDS_DYNAMIC_NULL.upper() : MODEL_PCD_DYNAMIC,
1493 TAB_PCDS_DYNAMIC_EX_NULL.upper() : MODEL_PCD_DYNAMIC_EX,
1494 }
1495
1496 ## Constructor of DecParser
1497 #
1498 # Initialize object of DecParser
1499 #
1500 # @param FilePath The path of platform description file
1501 # @param FileType The raw data of DSC file
1502 # @param Table Database used to retrieve module/package information
1503 # @param Macros Macros used for replacement in file
1504 #
1505 def __init__(self, FilePath, FileType, Table):
1506 # prevent re-initialization
1507 if hasattr(self, "_Table"):
1508 return
1509 MetaFileParser.__init__(self, FilePath, FileType, Table)
1510 self._Comments = []
1511 self._Version = 0x00010005 # Only EDK2 dec file is supported
1512 self.TblFile = EccGlobalData.gDb.TblFile
1513 self.FileID = -1
1514
1515 ## Parser starter
1516 def Start(self):
1517 Content = ''
1518 try:
1519 Content = open(str(self.MetaFile), 'r').readlines()
1520 except:
1521 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
1522
1523 #
1524 # Insert a record for file
1525 #
1526 Filename = NormPath(self.MetaFile)
1527 FileID = self.TblFile.GetFileId(Filename)
1528 if FileID:
1529 self.FileID = FileID
1530 else:
1531 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DEC)
1532
1533 for Index in range(0, len(Content)):
1534 Line, Comment = CleanString2(Content[Index])
1535 self._CurrentLine = Line
1536 self._LineIndex = Index
1537
1538 # save comment for later use
1539 if Comment:
1540 self._Comments.append((Comment, self._LineIndex+1))
1541 # skip empty line
1542 if Line == '':
1543 continue
1544
1545 # section header
1546 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
1547 self._SectionHeaderParser()
1548 self._Comments = []
1549 continue
1550 elif len(self._SectionType) == 0:
1551 self._Comments = []
1552 continue
1553
1554 # section content
1555 self._ValueList = ['', '', '']
1556 self._SectionParser[self._SectionType[0]](self)
1557 if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
1558 self._ItemType = -1
1559 self._Comments = []
1560 continue
1561
1562 #
1563 # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
1564 # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
1565 #
1566 for Arch, ModuleType, Type in self._Scope:
1567 self._LastItem = self._Store(
1568 Type,
1569 self._ValueList[0],
1570 self._ValueList[1],
1571 self._ValueList[2],
1572 Arch,
1573 ModuleType,
1574 self._Owner[-1],
1575 self.FileID,
1576 self._LineIndex+1,
1577 -1,
1578 self._LineIndex+1,
1579 -1,
1580 0
1581 )
1582 for Comment, LineNo in self._Comments:
1583 self._Store(
1584 MODEL_META_DATA_COMMENT,
1585 Comment,
1586 self._ValueList[0],
1587 self._ValueList[1],
1588 Arch,
1589 ModuleType,
1590 self._LastItem,
1591 self.FileID,
1592 LineNo,
1593 -1,
1594 LineNo,
1595 -1,
1596 0
1597 )
1598 self._Comments = []
1599 self._Done()
1600
1601 def _GetApplicableSectionMacro(self):
1602 Macros = {}
1603 for S1, S2, SectionType in self._Scope:
1604 for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", S2), (S1, "COMMON"), (S1, S2)]:
1605 if (SectionType, Scope1, Scope2) in self._SectionsMacroDict:
1606 Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
1607 return Macros
1608
1609 ## Section header parser
1610 #
1611 # The section header is always in following format:
1612 #
1613 # [section_name.arch<.platform|module_type>]
1614 #
1615 def _SectionHeaderParser(self):
1616 self._Scope = []
1617 self._SectionName = ''
1618 self._SectionType = []
1619 ArchList = set()
1620 for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
1621 if Item == '':
1622 continue
1623 ItemList = GetSplitValueList(Item, TAB_SPLIT)
1624
1625 # different types of PCD are permissible in one section
1626 self._SectionName = ItemList[0].upper()
1627 if self._SectionName in self.DataType:
1628 if self.DataType[self._SectionName] not in self._SectionType:
1629 self._SectionType.append(self.DataType[self._SectionName])
1630 else:
1631 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
1632 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1633 continue
1634
1635 if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
1636 EdkLogger.error(
1637 'Parser',
1638 FORMAT_INVALID,
1639 "%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
1640 File=self.MetaFile,
1641 Line=self._LineIndex+1,
1642 ExtraData=self._CurrentLine
1643 )
1644 # S1 is always Arch
1645 if len(ItemList) > 1:
1646 S1 = ItemList[1].upper()
1647 else:
1648 S1 = 'COMMON'
1649 ArchList.add(S1)
1650 # S2 may be Platform or ModuleType
1651 if len(ItemList) > 2:
1652 S2 = ItemList[2].upper()
1653 else:
1654 S2 = 'COMMON'
1655 if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
1656 self._Scope.append([S1, S2, self.DataType[self._SectionName]])
1657
1658 # 'COMMON' must not be used with specific ARCHs at the same section
1659 if 'COMMON' in ArchList and len(ArchList) > 1:
1660 EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
1661 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1662
1663 ## [guids], [ppis] and [protocols] section parser
1664 @ParseMacro
1665 def _GuidParser(self):
1666 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1667 if len(TokenList) < 2:
1668 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
1669 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1670 File=self.MetaFile, Line=self._LineIndex+1)
1671 if TokenList[0] == '':
1672 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
1673 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1674 File=self.MetaFile, Line=self._LineIndex+1)
1675 if TokenList[1] == '':
1676 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
1677 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1678 File=self.MetaFile, Line=self._LineIndex+1)
1679 if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
1680 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1681 ExtraData=self._CurrentLine + \
1682 " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1683 File=self.MetaFile, Line=self._LineIndex+1)
1684 self._ValueList[0] = TokenList[0]
1685 #Parse the Guid value format
1686 GuidValueList = TokenList[1].strip(' {}').split(',')
1687 Index = 0
1688 HexList = []
1689 if len(GuidValueList) == 11:
1690 for GuidValue in GuidValueList:
1691 GuidValue = GuidValue.strip()
1692 if GuidValue.startswith('0x') or GuidValue.startswith('0X'):
1693 HexList.append('0x' + str(GuidValue[2:]))
1694 Index += 1
1695 continue
1696 else:
1697 if GuidValue.startswith('{'):
1698 GuidValue = GuidValue.lstrip(' {')
1699 HexList.append('0x' + str(GuidValue[2:]))
1700 Index += 1
1701 self._ValueList[1] = "{ %s, %s, %s, { %s, %s, %s, %s, %s, %s, %s, %s }}" % (HexList[0], HexList[1], HexList[2], HexList[3], HexList[4], HexList[5], HexList[6], HexList[7], HexList[8], HexList[9], HexList[10])
1702 else:
1703 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1704 ExtraData=self._CurrentLine + \
1705 " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1706 File=self.MetaFile, Line=self._LineIndex+1)
1707 self._ValueList[0] = ''
1708
1709 ## PCD sections parser
1710 #
1711 # [PcdsFixedAtBuild]
1712 # [PcdsPatchableInModule]
1713 # [PcdsFeatureFlag]
1714 # [PcdsDynamicEx
1715 # [PcdsDynamic]
1716 #
1717 @ParseMacro
1718 def _PcdParser(self):
1719 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1720 self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1721 # check PCD information
1722 if self._ValueList[0] == '' or self._ValueList[1] == '':
1723 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1724 ExtraData=self._CurrentLine + \
1725 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1726 File=self.MetaFile, Line=self._LineIndex+1)
1727 # check PCD datum information
1728 if len(TokenList) < 2 or TokenList[1] == '':
1729 EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
1730 ExtraData=self._CurrentLine + \
1731 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1732 File=self.MetaFile, Line=self._LineIndex+1)
1733
1734
1735 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
1736 PtrValue = ValueRe.findall(TokenList[1])
1737
1738 # Has VOID* type string, may contain "|" character in the string.
1739 if len(PtrValue) != 0:
1740 ptrValueList = re.sub(ValueRe, '', TokenList[1])
1741 ValueList = GetSplitValueList(ptrValueList)
1742 ValueList[0] = PtrValue[0]
1743 else:
1744 ValueList = GetSplitValueList(TokenList[1])
1745
1746
1747 # check if there's enough datum information given
1748 if len(ValueList) != 3:
1749 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
1750 ExtraData=self._CurrentLine + \
1751 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1752 File=self.MetaFile, Line=self._LineIndex+1)
1753 # check default value
1754 if ValueList[0] == '':
1755 EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
1756 ExtraData=self._CurrentLine + \
1757 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1758 File=self.MetaFile, Line=self._LineIndex+1)
1759 # check datum type
1760 if ValueList[1] == '':
1761 EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
1762 ExtraData=self._CurrentLine + \
1763 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1764 File=self.MetaFile, Line=self._LineIndex+1)
1765 # check token of the PCD
1766 if ValueList[2] == '':
1767 EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
1768 ExtraData=self._CurrentLine + \
1769 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1770 File=self.MetaFile, Line=self._LineIndex+1)
1771 # check format of default value against the datum type
1772 IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
1773 if not IsValid:
1774 EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
1775 File=self.MetaFile, Line=self._LineIndex+1)
1776
1777 if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1778 # check Description, Prompt information
1779 PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
1780 PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
1781 Description = None
1782 Prompt = None
1783 # check @ValidRange, @ValidList and @Expression format valid
1784 ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
1785 PatternValidRangeIn = '(NOT)?\s*(\d+\s*-\s*\d+|0[xX][a-fA-F0-9]+\s*-\s*0[xX][a-fA-F0-9]+|LT\s*\d+|LT\s*0[xX][a-fA-F0-9]+|GT\s*\d+|GT\s*0[xX][a-fA-F0-9]+|LE\s*\d+|LE\s*0[xX][a-fA-F0-9]+|GE\s*\d+|GE\s*0[xX][a-fA-F0-9]+|XOR\s*\d+|XOR\s*0[xX][a-fA-F0-9]+|EQ\s*\d+|EQ\s*0[xX][a-fA-F0-9]+)'
1786 PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
1787 for Comment in self._Comments:
1788 Comm = Comment[0].strip()
1789 if not Comm:
1790 continue
1791 if not Description:
1792 Description = PatternDesc.findall(Comm)
1793 if not Prompt:
1794 Prompt = PatternPrompt.findall(Comm)
1795 if Comm[0] == '#':
1796 ValidFormt = Comm.lstrip('#')
1797 ValidFormt = ValidFormt.lstrip()
1798 if ValidFormt[0:11] == '@ValidRange':
1799 ValidFormt = ValidFormt[11:]
1800 ValidFormt = ValidFormt.lstrip()
1801 try:
1802 ErrorCode, Expression = ValidFormt.split('|', 1)
1803 except ValueError:
1804 ErrorCode = '0x0'
1805 Expression = ValidFormt
1806 ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1807 try:
1808 if not eval(ErrorCodeValid % ErrorCode):
1809 EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1810 except:
1811 EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1812 if not PatternValidRng.search(Expression):
1813 EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
1814 if ValidFormt[0:10] == '@ValidList':
1815 ValidFormt = ValidFormt[10:]
1816 ValidFormt = ValidFormt.lstrip()
1817 try:
1818 ErrorCode, Expression = ValidFormt.split('|', 1)
1819 except ValueError:
1820 ErrorCode = '0x0'
1821 Expression = ValidFormt
1822 ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1823 try:
1824 if not eval(ErrorCodeValid % ErrorCode):
1825 EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1826 except:
1827 EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1828 Values = Expression.split(',')
1829 for Value in Values:
1830 Value = Value.strip()
1831 try:
1832 eval(Value)
1833 except:
1834 EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
1835 break
1836 if ValidFormt[0:11] == '@Expression':
1837 ValidFormt = ValidFormt[11:]
1838 ValidFormt = ValidFormt.lstrip()
1839 try:
1840 ErrorCode, Expression = ValidFormt.split('|', 1)
1841 except ValueError:
1842 ErrorCode = '0x0'
1843 Expression = ValidFormt
1844 ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1845 try:
1846 if not eval(ErrorCodeValid % ErrorCode):
1847 EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1848 except:
1849 EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1850 if not Expression:
1851 EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
1852 if not Description:
1853 EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
1854 if not Prompt:
1855 EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
1856 # check Description, Prompt localization information
1857 if self._UniObj:
1858 self._UniObj.CheckPcdInfo(TokenList[0])
1859
1860 if ValueList[0] in ['True', 'true', 'TRUE']:
1861 ValueList[0] = '1'
1862 elif ValueList[0] in ['False', 'false', 'FALSE']:
1863 ValueList[0] = '0'
1864
1865 self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
1866
1867 _SectionParser = {
1868 MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
1869 MODEL_EFI_INCLUDE : MetaFileParser._PathParser,
1870 MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
1871 MODEL_EFI_GUID : _GuidParser,
1872 MODEL_EFI_PPI : _GuidParser,
1873 MODEL_EFI_PROTOCOL : _GuidParser,
1874 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
1875 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
1876 MODEL_PCD_FEATURE_FLAG : _PcdParser,
1877 MODEL_PCD_DYNAMIC : _PcdParser,
1878 MODEL_PCD_DYNAMIC_EX : _PcdParser,
1879 MODEL_UNKNOWN : MetaFileParser._Skip,
1880 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
1881 }
1882
1883
1884 ## Fdf
1885 #
1886 # This class defined the structure used in Fdf object
1887 #
1888 # @param Filename: Input value for Ffilename of Fdf file, default is None
1889 # @param WorkspaceDir: Input value for current workspace directory, default is None
1890 #
1891 class Fdf(object):
1892 def __init__(self, Filename = None, IsToDatabase = False, WorkspaceDir = None, Database = None):
1893 self.WorkspaceDir = WorkspaceDir
1894 self.IsToDatabase = IsToDatabase
1895
1896 self.Cur = Database.Cur
1897 self.TblFile = Database.TblFile
1898 self.TblFdf = Database.TblFdf
1899 self.FileID = -1
1900 self.FileList = {}
1901
1902 #
1903 # Load Fdf file if filename is not None
1904 #
1905 if Filename is not None:
1906 try:
1907 self.LoadFdfFile(Filename)
1908 except Exception:
1909 pass
1910
1911 #
1912 # Insert a FDF file record into database
1913 #
1914 def InsertFile(self, Filename):
1915 FileID = -1
1916 Filename = NormPath(Filename)
1917 if Filename not in self.FileList:
1918 FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_FDF)
1919 self.FileList[Filename] = FileID
1920
1921 return self.FileList[Filename]
1922
1923
1924 ## Load Fdf file
1925 #
1926 # Load the file if it exists
1927 #
1928 # @param Filename: Input value for filename of Fdf file
1929 #
1930 def LoadFdfFile(self, Filename):
1931 FileList = []
1932 #
1933 # Parse Fdf file
1934 #
1935 Filename = NormPath(Filename)
1936 Fdf = FdfParser(Filename)
1937 Fdf.ParseFile()
1938
1939 #
1940 # Insert inf file and pcd information
1941 #
1942 if self.IsToDatabase:
1943 (Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled) = \
1944 (0, '', '', '', 'COMMON', 'COMMON', -1, -1, -1, -1, -1, -1, 0)
1945 for Index in range(0, len(Fdf.Profile.PcdDict)):
1946 pass
1947 for Key in Fdf.Profile.PcdDict.keys():
1948 Model = MODEL_PCD
1949 Value1 = Key[1]
1950 Value2 = Key[0]
1951 FileName = Fdf.Profile.PcdFileLineDict[Key][0]
1952 StartLine = Fdf.Profile.PcdFileLineDict[Key][1]
1953 BelongsToFile = self.InsertFile(FileName)
1954 self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1955 for Index in range(0, len(Fdf.Profile.InfList)):
1956 Model = MODEL_META_DATA_COMPONENT
1957 Value1 = Fdf.Profile.InfList[Index]
1958 Value2 = ''
1959 FileName = Fdf.Profile.InfFileLineList[Index][0]
1960 StartLine = Fdf.Profile.InfFileLineList[Index][1]
1961 BelongsToFile = self.InsertFile(FileName)
1962 self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1963
1964 class UniParser(object):
1965 # IsExtraUni defined the UNI file is Module UNI or extra Module UNI
1966 # IsModuleUni defined the UNI file is Module UNI or Package UNI
1967 def __init__(self, FilePath, IsExtraUni=False, IsModuleUni=True):
1968 self.FilePath = FilePath
1969 self.FileName = os.path.basename(FilePath)
1970 self.IsExtraUni = IsExtraUni
1971 self.IsModuleUni = IsModuleUni
1972 self.FileIn = None
1973 self.Missing = []
1974 self.__read()
1975
1976 def __read(self):
1977 try:
1978 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_8').read()
1979 except UnicodeError:
1980 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16').read()
1981 except UnicodeError:
1982 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16_le').read()
1983 except IOError:
1984 self.FileIn = ""
1985
1986 def Start(self):
1987 if self.IsModuleUni:
1988 if self.IsExtraUni:
1989 ModuleName = self.CheckKeyValid('STR_PROPERTIES_MODULE_NAME')
1990 self.PrintLog('STR_PROPERTIES_MODULE_NAME', ModuleName)
1991 else:
1992 ModuleAbstract = self.CheckKeyValid('STR_MODULE_ABSTRACT')
1993 self.PrintLog('STR_MODULE_ABSTRACT', ModuleAbstract)
1994 ModuleDescription = self.CheckKeyValid('STR_MODULE_DESCRIPTION')
1995 self.PrintLog('STR_MODULE_DESCRIPTION', ModuleDescription)
1996 else:
1997 if self.IsExtraUni:
1998 PackageName = self.CheckKeyValid('STR_PROPERTIES_PACKAGE_NAME')
1999 self.PrintLog('STR_PROPERTIES_PACKAGE_NAME', PackageName)
2000 else:
2001 PackageAbstract = self.CheckKeyValid('STR_PACKAGE_ABSTRACT')
2002 self.PrintLog('STR_PACKAGE_ABSTRACT', PackageAbstract)
2003 PackageDescription = self.CheckKeyValid('STR_PACKAGE_DESCRIPTION')
2004 self.PrintLog('STR_PACKAGE_DESCRIPTION', PackageDescription)
2005
2006 def CheckKeyValid(self, Key, Contents=None):
2007 if not Contents:
2008 Contents = self.FileIn
2009 KeyPattern = re.compile('#string\s+%s\s+.*?#language.*?".*?"' % Key, re.S)
2010 if KeyPattern.search(Contents):
2011 return True
2012 return False
2013
2014 def CheckPcdInfo(self, PcdCName):
2015 PromptKey = 'STR_%s_PROMPT' % PcdCName.replace('.', '_')
2016 PcdPrompt = self.CheckKeyValid(PromptKey)
2017 self.PrintLog(PromptKey, PcdPrompt)
2018 HelpKey = 'STR_%s_HELP' % PcdCName.replace('.', '_')
2019 PcdHelp = self.CheckKeyValid(HelpKey)
2020 self.PrintLog(HelpKey, PcdHelp)
2021
2022 def PrintLog(self, Key, Value):
2023 if not Value and Key not in self.Missing:
2024 Msg = '%s is missing in the %s file.' % (Key, self.FileName)
2025 EdkLogger.warn('Parser', Msg)
2026 EccGlobalData.gDb.TblReport.Insert(EccToolError.ERROR_GENERAL_CHECK_UNI_HELP_INFO, OtherMsg=Msg, BelongsToTable='File', BelongsToItem=-2)
2027 self.Missing.append(Key)
2028
2029 ##
2030 #
2031 # This acts like the main() function for the script, unless it is 'import'ed into another
2032 # script.
2033 #
2034 if __name__ == '__main__':
2035 pass
2036