]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Ecc/MetaFileWorkspace/MetaFileParser.py
52a78bcbb81391192faad614542ed35c1041916a
[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 = 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 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 if Value.upper().find('$(EFI_SOURCE)\Edk'.upper()) > -1 or Value.upper().find('$(EFI_SOURCE)/Edk'.upper()) > -1:
614 Value = '$(EDK_SOURCE)' + Value[17:]
615 if Value.find('$(EFI_SOURCE)') > -1 or Value.find('$(EDK_SOURCE)') > -1:
616 pass
617 elif Value.startswith('.'):
618 pass
619 elif Value.startswith('$('):
620 pass
621 else:
622 Value = '$(EFI_SOURCE)/' + Value
623
624 self._ValueList[Index] = ReplaceMacro(Value, Macros)
625
626 ## Parse [Sources] section
627 #
628 # Only path can have macro used. So we need to replace them before use.
629 #
630 @ParseMacro
631 def _SourceFileParser(self):
632 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
633 self._ValueList[0:len(TokenList)] = TokenList
634 Macros = self._Macros
635 # For Acpi tables, remove macro like ' TABLE_NAME=Sata1'
636 if 'COMPONENT_TYPE' in Macros:
637 if self._Defines['COMPONENT_TYPE'].upper() == 'ACPITABLE':
638 self._ValueList[0] = GetSplitValueList(self._ValueList[0], ' ', 1)[0]
639 if self._Defines['BASE_NAME'] == 'Microcode':
640 pass
641 self._ValueList = [ReplaceMacro(Value, Macros) for Value in self._ValueList]
642
643 ## Parse [Binaries] section
644 #
645 # Only path can have macro used. So we need to replace them before use.
646 #
647 @ParseMacro
648 def _BinaryFileParser(self):
649 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 2)
650 if len(TokenList) < 2:
651 EdkLogger.error('Parser', FORMAT_INVALID, "No file type or path specified",
652 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
653 File=self.MetaFile, Line=self._LineIndex+1)
654 if not TokenList[0]:
655 EdkLogger.error('Parser', FORMAT_INVALID, "No file type specified",
656 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
657 File=self.MetaFile, Line=self._LineIndex+1)
658 if not TokenList[1]:
659 EdkLogger.error('Parser', FORMAT_INVALID, "No file path specified",
660 ExtraData=self._CurrentLine + " (<FileType> | <FilePath> [| <Target>])",
661 File=self.MetaFile, Line=self._LineIndex+1)
662 self._ValueList[0:len(TokenList)] = TokenList
663 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
664
665 ## [nmake] section parser (Edk.x style only)
666 def _NmakeParser(self):
667 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
668 self._ValueList[0:len(TokenList)] = TokenList
669 # remove macros
670 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros)
671 # remove self-reference in macro setting
672 #self._ValueList[1] = ReplaceMacro(self._ValueList[1], {self._ValueList[0]:''})
673
674 ## [FixedPcd], [FeaturePcd], [PatchPcd], [Pcd] and [PcdEx] sections parser
675 @ParseMacro
676 def _PcdParser(self):
677 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
678 ValueList = GetSplitValueList(TokenList[0], TAB_SPLIT)
679 if len(ValueList) != 2:
680 EdkLogger.error('Parser', FORMAT_INVALID, "Illegal token space GUID and PCD name format",
681 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
682 File=self.MetaFile, Line=self._LineIndex+1)
683 self._ValueList[0:1] = ValueList
684 if len(TokenList) > 1:
685 self._ValueList[2] = TokenList[1]
686 if self._ValueList[0] == '' or self._ValueList[1] == '':
687 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
688 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<PcdCName>)",
689 File=self.MetaFile, Line=self._LineIndex+1)
690
691 # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
692 if self._ValueList[2] != '':
693 InfPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
694 if InfPcdValueList[0] in ['True', 'true', 'TRUE']:
695 self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '1', 1);
696 elif InfPcdValueList[0] in ['False', 'false', 'FALSE']:
697 self._ValueList[2] = TokenList[1].replace(InfPcdValueList[0], '0', 1);
698
699 ## [depex] section parser
700 @ParseMacro
701 def _DepexParser(self):
702 self._ValueList[0:1] = [self._CurrentLine]
703
704 _SectionParser = {
705 MODEL_UNKNOWN : MetaFileParser._Skip,
706 MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
707 MODEL_META_DATA_BUILD_OPTION : MetaFileParser._BuildOptionParser,
708 MODEL_EFI_INCLUDE : _IncludeParser, # for Edk.x modules
709 MODEL_EFI_LIBRARY_INSTANCE : MetaFileParser._CommonParser, # for Edk.x modules
710 MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
711 MODEL_META_DATA_PACKAGE : MetaFileParser._PathParser,
712 MODEL_META_DATA_NMAKE : _NmakeParser, # for Edk.x modules
713 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
714 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
715 MODEL_PCD_FEATURE_FLAG : _PcdParser,
716 MODEL_PCD_DYNAMIC_EX : _PcdParser,
717 MODEL_PCD_DYNAMIC : _PcdParser,
718 MODEL_EFI_SOURCE_FILE : _SourceFileParser,
719 MODEL_EFI_GUID : MetaFileParser._CommonParser,
720 MODEL_EFI_PROTOCOL : MetaFileParser._CommonParser,
721 MODEL_EFI_PPI : MetaFileParser._CommonParser,
722 MODEL_EFI_DEPEX : _DepexParser,
723 MODEL_EFI_BINARY_FILE : _BinaryFileParser,
724 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
725 }
726
727 ## DSC file parser class
728 #
729 # @param FilePath The path of platform description file
730 # @param FileType The raw data of DSC file
731 # @param Table Database used to retrieve module/package information
732 # @param Macros Macros used for replacement in file
733 # @param Owner Owner ID (for sub-section parsing)
734 # @param From ID from which the data comes (for !INCLUDE directive)
735 #
736 class DscParser(MetaFileParser):
737 # DSC file supported data types (one type per section)
738 DataType = {
739 TAB_SKUIDS.upper() : MODEL_EFI_SKU_ID,
740 TAB_LIBRARIES.upper() : MODEL_EFI_LIBRARY_INSTANCE,
741 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
742 TAB_BUILD_OPTIONS.upper() : MODEL_META_DATA_BUILD_OPTION,
743 TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
744 TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
745 TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
746 TAB_PCDS_DYNAMIC_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_DEFAULT,
747 TAB_PCDS_DYNAMIC_HII_NULL.upper() : MODEL_PCD_DYNAMIC_HII,
748 TAB_PCDS_DYNAMIC_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_VPD,
749 TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL.upper() : MODEL_PCD_DYNAMIC_EX_DEFAULT,
750 TAB_PCDS_DYNAMIC_EX_HII_NULL.upper() : MODEL_PCD_DYNAMIC_EX_HII,
751 TAB_PCDS_DYNAMIC_EX_VPD_NULL.upper() : MODEL_PCD_DYNAMIC_EX_VPD,
752 TAB_COMPONENTS.upper() : MODEL_META_DATA_COMPONENT,
753 TAB_COMPONENTS_SOURCE_OVERRIDE_PATH.upper() : MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH,
754 TAB_DSC_DEFINES.upper() : MODEL_META_DATA_HEADER,
755 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
756 TAB_DSC_DEFINES_EDKGLOBAL : MODEL_META_DATA_GLOBAL_DEFINE,
757 TAB_INCLUDE.upper() : MODEL_META_DATA_INCLUDE,
758 TAB_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
759 TAB_IF_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
760 TAB_IF_N_DEF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF,
761 TAB_ELSE_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF,
762 TAB_ELSE.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
763 TAB_END_IF.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF,
764 TAB_ERROR.upper() : MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR,
765 }
766
767 # Valid names in define section
768 DefineKeywords = [
769 "DSC_SPECIFICATION",
770 "PLATFORM_NAME",
771 "PLATFORM_GUID",
772 "PLATFORM_VERSION",
773 "SKUID_IDENTIFIER",
774 "PCD_INFO_GENERATION",
775 "SUPPORTED_ARCHITECTURES",
776 "BUILD_TARGETS",
777 "OUTPUT_DIRECTORY",
778 "FLASH_DEFINITION",
779 "BUILD_NUMBER",
780 "RFC_LANGUAGES",
781 "ISO_LANGUAGES",
782 "TIME_STAMP_FILE",
783 "VPD_TOOL_GUID",
784 "FIX_LOAD_TOP_MEMORY_ADDRESS"
785 ]
786
787 SubSectionDefineKeywords = [
788 "FILE_GUID"
789 ]
790
791 SymbolPattern = ValueExpression.SymbolPattern
792
793 ## Constructor of DscParser
794 #
795 # Initialize object of DscParser
796 #
797 # @param FilePath The path of platform description file
798 # @param FileType The raw data of DSC file
799 # @param Table Database used to retrieve module/package information
800 # @param Macros Macros used for replacement in file
801 # @param Owner Owner ID (for sub-section parsing)
802 # @param From ID from which the data comes (for !INCLUDE directive)
803 #
804 def __init__(self, FilePath, FileType, Table, Owner=-1, From=-1):
805 # prevent re-initialization
806 if hasattr(self, "_Table"):
807 return
808 MetaFileParser.__init__(self, FilePath, FileType, Table, Owner, From)
809 self._Version = 0x00010005 # Only EDK2 dsc file is supported
810 # to store conditional directive evaluation result
811 self._DirectiveStack = []
812 self._DirectiveEvalStack = []
813 self._Enabled = 1
814
815 # Final valid replacable symbols
816 self._Symbols = {}
817 #
818 # Map the ID between the original table and new table to track
819 # the owner item
820 #
821 self._IdMapping = {-1:-1}
822
823 self.TblFile = EccGlobalData.gDb.TblFile
824 self.FileID = -1
825
826 ## Parser starter
827 def Start(self):
828 Content = ''
829 try:
830 Content = open(str(self.MetaFile.Path), 'r').readlines()
831 except:
832 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
833 #
834 # Insert a record for file
835 #
836 Filename = NormPath(self.MetaFile.Path)
837 FileID = self.TblFile.GetFileId(Filename)
838 if FileID:
839 self.FileID = FileID
840 else:
841 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DSC)
842
843
844 for Index in range(0, len(Content)):
845 Line = CleanString(Content[Index])
846 # skip empty line
847 if Line == '':
848 continue
849
850 self._CurrentLine = Line
851 self._LineIndex = Index
852 if self._InSubsection and self._Owner[-1] == -1:
853 self._Owner.append(self._LastItem)
854
855 # section header
856 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
857 self._SectionType = MODEL_META_DATA_SECTION_HEADER
858 # subsection ending
859 elif Line[0] == '}' and self._InSubsection:
860 self._InSubsection = False
861 self._SubsectionType = MODEL_UNKNOWN
862 self._SubsectionName = ''
863 self._Owner[-1] = -1
864 continue
865 # subsection header
866 elif Line[0] == TAB_OPTION_START and Line[-1] == TAB_OPTION_END:
867 self._SubsectionType = MODEL_META_DATA_SUBSECTION_HEADER
868 # directive line
869 elif Line[0] == '!':
870 self._DirectiveParser()
871 continue
872
873 if self._InSubsection:
874 SectionType = self._SubsectionType
875 else:
876 SectionType = self._SectionType
877 self._ItemType = SectionType
878
879 self._ValueList = ['', '', '']
880 self._SectionParser[SectionType](self)
881 if self._ValueList is None:
882 continue
883 #
884 # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
885 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
886 #
887 for Arch, ModuleType in self._Scope:
888 self._LastItem = self._Store(
889 self._ItemType,
890 self._ValueList[0],
891 self._ValueList[1],
892 self._ValueList[2],
893 Arch,
894 ModuleType,
895 self._Owner[-1],
896 self.FileID,
897 self._From,
898 self._LineIndex+1,
899 -1,
900 self._LineIndex+1,
901 -1,
902 self._Enabled
903 )
904
905 if self._DirectiveStack:
906 Type, Line, Text = self._DirectiveStack[-1]
907 EdkLogger.error('Parser', FORMAT_INVALID, "No matching '!endif' found",
908 ExtraData=Text, File=self.MetaFile, Line=Line)
909 self._Done()
910
911 ## <subsection_header> parser
912 def _SubsectionHeaderParser(self):
913 self._SubsectionName = self._CurrentLine[1:-1].upper()
914 if self._SubsectionName in self.DataType:
915 self._SubsectionType = self.DataType[self._SubsectionName]
916 else:
917 self._SubsectionType = MODEL_UNKNOWN
918 EdkLogger.warn("Parser", "Unrecognized sub-section", File=self.MetaFile,
919 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
920 self._ValueList[0] = self._SubsectionName
921
922 ## Directive statement parser
923 def _DirectiveParser(self):
924 self._ValueList = ['', '', '']
925 TokenList = GetSplitValueList(self._CurrentLine, ' ', 1)
926 self._ValueList[0:len(TokenList)] = TokenList
927
928 # Syntax check
929 DirectiveName = self._ValueList[0].upper()
930 if DirectiveName not in self.DataType:
931 EdkLogger.error("Parser", FORMAT_INVALID, "Unknown directive [%s]" % DirectiveName,
932 File=self.MetaFile, Line=self._LineIndex+1)
933 if DirectiveName in ['!IF', '!IFDEF', '!INCLUDE', '!IFNDEF', '!ELSEIF'] and self._ValueList[1] == '':
934 EdkLogger.error("Parser", FORMAT_INVALID, "Missing expression",
935 File=self.MetaFile, Line=self._LineIndex+1,
936 ExtraData=self._CurrentLine)
937
938 ItemType = self.DataType[DirectiveName]
939 if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
940 # Remove all directives between !if and !endif, including themselves
941 while self._DirectiveStack:
942 # Remove any !else or !elseif
943 DirectiveInfo = self._DirectiveStack.pop()
944 if DirectiveInfo[0] in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
945 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
946 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
947 break
948 else:
949 EdkLogger.error("Parser", FORMAT_INVALID, "Redundant '!endif'",
950 File=self.MetaFile, Line=self._LineIndex+1,
951 ExtraData=self._CurrentLine)
952 elif ItemType != MODEL_META_DATA_INCLUDE:
953 # Break if there's a !else is followed by a !elseif
954 if ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF and \
955 self._DirectiveStack and \
956 self._DirectiveStack[-1][0] == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
957 EdkLogger.error("Parser", FORMAT_INVALID, "'!elseif' after '!else'",
958 File=self.MetaFile, Line=self._LineIndex+1,
959 ExtraData=self._CurrentLine)
960 self._DirectiveStack.append((ItemType, self._LineIndex+1, self._CurrentLine))
961 elif self._From > 0:
962 EdkLogger.error('Parser', FORMAT_INVALID,
963 "No '!include' allowed in included file",
964 ExtraData=self._CurrentLine, File=self.MetaFile,
965 Line=self._LineIndex+1)
966
967 #
968 # Model, Value1, Value2, Value3, Arch, ModuleType, BelongsToItem=-1, BelongsToFile=-1,
969 # LineBegin=-1, ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, Enabled=-1
970 #
971 self._LastItem = self._Store(
972 ItemType,
973 self._ValueList[0],
974 self._ValueList[1],
975 self._ValueList[2],
976 'COMMON',
977 'COMMON',
978 self._Owner[-1],
979 self.FileID,
980 self._From,
981 self._LineIndex+1,
982 -1,
983 self._LineIndex+1,
984 -1,
985 0
986 )
987
988 ## [defines] section parser
989 @ParseMacro
990 def _DefineParser(self):
991 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
992 self._ValueList[1:len(TokenList)] = TokenList
993
994 # Syntax check
995 if not self._ValueList[1]:
996 EdkLogger.error('Parser', FORMAT_INVALID, "No name specified",
997 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
998 if not self._ValueList[2]:
999 EdkLogger.error('Parser', FORMAT_INVALID, "No value specified",
1000 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1001 if (not self._ValueList[1] in self.DefineKeywords and
1002 (self._InSubsection and self._ValueList[1] not in self.SubSectionDefineKeywords)):
1003 EdkLogger.error('Parser', FORMAT_INVALID,
1004 "Unknown keyword found: %s. "
1005 "If this is a macro you must "
1006 "add it as a DEFINE in the DSC" % self._ValueList[1],
1007 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1008 self._Defines[self._ValueList[1]] = self._ValueList[2]
1009 self._ItemType = self.DataType[TAB_DSC_DEFINES.upper()]
1010
1011 @ParseMacro
1012 def _SkuIdParser(self):
1013 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1014 if len(TokenList) != 2:
1015 EdkLogger.error('Parser', FORMAT_INVALID, "Correct format is '<Integer>|<UiName>'",
1016 ExtraData=self._CurrentLine, File=self.MetaFile, Line=self._LineIndex+1)
1017 self._ValueList[0:len(TokenList)] = TokenList
1018
1019 ## Parse Edk style of library modules
1020 def _LibraryInstanceParser(self):
1021 self._ValueList[0] = self._CurrentLine
1022
1023 ## PCD sections parser
1024 #
1025 # [PcdsFixedAtBuild]
1026 # [PcdsPatchableInModule]
1027 # [PcdsFeatureFlag]
1028 # [PcdsDynamicEx
1029 # [PcdsDynamicExDefault]
1030 # [PcdsDynamicExVpd]
1031 # [PcdsDynamicExHii]
1032 # [PcdsDynamic]
1033 # [PcdsDynamicDefault]
1034 # [PcdsDynamicVpd]
1035 # [PcdsDynamicHii]
1036 #
1037 @ParseMacro
1038 def _PcdParser(self):
1039 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1040 self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1041 if len(TokenList) == 2:
1042 self._ValueList[2] = TokenList[1]
1043 if self._ValueList[0] == '' or self._ValueList[1] == '':
1044 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1045 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1046 File=self.MetaFile, Line=self._LineIndex+1)
1047 if self._ValueList[2] == '':
1048 EdkLogger.error('Parser', FORMAT_INVALID, "No PCD value given",
1049 ExtraData=self._CurrentLine + " (<TokenSpaceGuidCName>.<TokenCName>|<PcdValue>)",
1050 File=self.MetaFile, Line=self._LineIndex+1)
1051 # if value are 'True', 'true', 'TRUE' or 'False', 'false', 'FALSE', replace with integer 1 or 0.
1052 DscPcdValueList = GetSplitValueList(TokenList[1], TAB_VALUE_SPLIT, 1)
1053 if DscPcdValueList[0] in ['True', 'true', 'TRUE']:
1054 self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '1', 1);
1055 elif DscPcdValueList[0] in ['False', 'false', 'FALSE']:
1056 self._ValueList[2] = TokenList[1].replace(DscPcdValueList[0], '0', 1);
1057
1058 ## [components] section parser
1059 @ParseMacro
1060 def _ComponentParser(self):
1061 if self._CurrentLine[-1] == '{':
1062 self._ValueList[0] = self._CurrentLine[0:-1].strip()
1063 self._InSubsection = True
1064 else:
1065 self._ValueList[0] = self._CurrentLine
1066
1067 ## [LibraryClasses] section
1068 @ParseMacro
1069 def _LibraryClassParser(self):
1070 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT)
1071 if len(TokenList) < 2:
1072 EdkLogger.error('Parser', FORMAT_INVALID, "No library class or instance specified",
1073 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1074 File=self.MetaFile, Line=self._LineIndex+1)
1075 if TokenList[0] == '':
1076 EdkLogger.error('Parser', FORMAT_INVALID, "No library class specified",
1077 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1078 File=self.MetaFile, Line=self._LineIndex+1)
1079 if TokenList[1] == '':
1080 EdkLogger.error('Parser', FORMAT_INVALID, "No library instance specified",
1081 ExtraData=self._CurrentLine + " (<LibraryClassName>|<LibraryInstancePath>)",
1082 File=self.MetaFile, Line=self._LineIndex+1)
1083
1084 self._ValueList[0:len(TokenList)] = TokenList
1085
1086 def _CompponentSourceOverridePathParser(self):
1087 self._ValueList[0] = self._CurrentLine
1088
1089 ## [BuildOptions] section parser
1090 @ParseMacro
1091 def _BuildOptionParser(self):
1092 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1093 TokenList2 = GetSplitValueList(TokenList[0], ':', 1)
1094 if len(TokenList2) == 2:
1095 self._ValueList[0] = TokenList2[0] # toolchain family
1096 self._ValueList[1] = TokenList2[1] # keys
1097 else:
1098 self._ValueList[1] = TokenList[0]
1099 if len(TokenList) == 2: # value
1100 self._ValueList[2] = TokenList[1]
1101
1102 if self._ValueList[1].count('_') != 4:
1103 EdkLogger.error(
1104 'Parser',
1105 FORMAT_INVALID,
1106 "'%s' must be in format of <TARGET>_<TOOLCHAIN>_<ARCH>_<TOOL>_FLAGS" % self._ValueList[1],
1107 ExtraData=self._CurrentLine,
1108 File=self.MetaFile,
1109 Line=self._LineIndex+1
1110 )
1111
1112 ## Override parent's method since we'll do all macro replacements in parser
1113 def _GetMacros(self):
1114 Macros = dict( [('ARCH', 'IA32'), ('FAMILY', TAB_COMPILER_MSFT), ('TOOL_CHAIN_TAG', 'VS2008x86'), ('TARGET', 'DEBUG')])
1115 Macros.update(self._FileLocalMacros)
1116 Macros.update(self._GetApplicableSectionMacro())
1117 Macros.update(GlobalData.gEdkGlobal)
1118 Macros.update(GlobalData.gPlatformDefines)
1119 Macros.update(GlobalData.gCommandLineDefines)
1120 # PCD cannot be referenced in macro definition
1121 if self._ItemType not in [MODEL_META_DATA_DEFINE, MODEL_META_DATA_GLOBAL_DEFINE]:
1122 Macros.update(self._Symbols)
1123 return Macros
1124
1125 def _PostProcess(self):
1126 Processer = {
1127 MODEL_META_DATA_SECTION_HEADER : self.__ProcessSectionHeader,
1128 MODEL_META_DATA_SUBSECTION_HEADER : self.__ProcessSubsectionHeader,
1129 MODEL_META_DATA_HEADER : self.__ProcessDefine,
1130 MODEL_META_DATA_DEFINE : self.__ProcessDefine,
1131 MODEL_META_DATA_GLOBAL_DEFINE : self.__ProcessDefine,
1132 MODEL_META_DATA_INCLUDE : self.__ProcessDirective,
1133 MODEL_META_DATA_CONDITIONAL_STATEMENT_IF : self.__ProcessDirective,
1134 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE : self.__ProcessDirective,
1135 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF : self.__ProcessDirective,
1136 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF : self.__ProcessDirective,
1137 MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF : self.__ProcessDirective,
1138 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF : self.__ProcessDirective,
1139 MODEL_EFI_SKU_ID : self.__ProcessSkuId,
1140 MODEL_EFI_LIBRARY_INSTANCE : self.__ProcessLibraryInstance,
1141 MODEL_EFI_LIBRARY_CLASS : self.__ProcessLibraryClass,
1142 MODEL_PCD_FIXED_AT_BUILD : self.__ProcessPcd,
1143 MODEL_PCD_PATCHABLE_IN_MODULE : self.__ProcessPcd,
1144 MODEL_PCD_FEATURE_FLAG : self.__ProcessPcd,
1145 MODEL_PCD_DYNAMIC_DEFAULT : self.__ProcessPcd,
1146 MODEL_PCD_DYNAMIC_HII : self.__ProcessPcd,
1147 MODEL_PCD_DYNAMIC_VPD : self.__ProcessPcd,
1148 MODEL_PCD_DYNAMIC_EX_DEFAULT : self.__ProcessPcd,
1149 MODEL_PCD_DYNAMIC_EX_HII : self.__ProcessPcd,
1150 MODEL_PCD_DYNAMIC_EX_VPD : self.__ProcessPcd,
1151 MODEL_META_DATA_COMPONENT : self.__ProcessComponent,
1152 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : self.__ProcessSourceOverridePath,
1153 MODEL_META_DATA_BUILD_OPTION : self.__ProcessBuildOption,
1154 MODEL_UNKNOWN : self._Skip,
1155 MODEL_META_DATA_USER_EXTENSION : self._Skip,
1156 MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR : self._Skip,
1157 }
1158
1159 self._RawTable = self._Table
1160 self._Table = MetaFileStorage(self._RawTable.Cur, self.MetaFile, MODEL_FILE_DSC, True)
1161 self._DirectiveStack = []
1162 self._DirectiveEvalStack = []
1163 self._FileWithError = self.MetaFile
1164 self._FileLocalMacros = {}
1165 self._SectionsMacroDict = {}
1166 GlobalData.gPlatformDefines = {}
1167
1168 # Get all macro and PCD which has straitforward value
1169 self.__RetrievePcdValue()
1170 self._Content = self._RawTable.GetAll()
1171 self._ContentIndex = 0
1172 while self._ContentIndex < len(self._Content) :
1173 Id, self._ItemType, V1, V2, V3, S1, S2, Owner, BelongsToFile, self._From, \
1174 LineStart, ColStart, LineEnd, ColEnd, Enabled = self._Content[self._ContentIndex]
1175
1176 if self._From < 0:
1177 self._FileWithError = self.MetaFile
1178
1179 self._ContentIndex += 1
1180
1181 self._Scope = [[S1, S2]]
1182 self._LineIndex = LineStart - 1
1183 self._ValueList = [V1, V2, V3]
1184
1185 try:
1186 Processer[self._ItemType]()
1187 except EvaluationException as Excpt:
1188 #
1189 # Only catch expression evaluation error here. We need to report
1190 # the precise number of line on which the error occurred
1191 #
1192 pass
1193 # EdkLogger.error('Parser', FORMAT_INVALID, "Invalid expression: %s" % str(Excpt),
1194 # File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1195 # Line=self._LineIndex+1)
1196 except MacroException as Excpt:
1197 EdkLogger.error('Parser', FORMAT_INVALID, str(Excpt),
1198 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1199 Line=self._LineIndex+1)
1200
1201 if self._ValueList is None:
1202 continue
1203
1204 NewOwner = self._IdMapping.get(Owner, -1)
1205 self._Enabled = int((not self._DirectiveEvalStack) or (False not in self._DirectiveEvalStack))
1206 self._LastItem = self._Store(
1207 self._ItemType,
1208 self._ValueList[0],
1209 self._ValueList[1],
1210 self._ValueList[2],
1211 S1,
1212 S2,
1213 NewOwner,
1214 BelongsToFile,
1215 self._From,
1216 self._LineIndex+1,
1217 -1,
1218 self._LineIndex+1,
1219 -1,
1220 self._Enabled
1221 )
1222 self._IdMapping[Id] = self._LastItem
1223
1224 RecordList = self._Table.GetAll()
1225
1226 self._RawTable.Drop()
1227 self._Table.Drop()
1228 for Record in RecordList:
1229 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])
1230 GlobalData.gPlatformDefines.update(self._FileLocalMacros)
1231 self._PostProcessed = True
1232 self._Content = None
1233
1234 def __ProcessSectionHeader(self):
1235 self._SectionName = self._ValueList[0]
1236 if self._SectionName in self.DataType:
1237 self._SectionType = self.DataType[self._SectionName]
1238 else:
1239 self._SectionType = MODEL_UNKNOWN
1240
1241 def __ProcessSubsectionHeader(self):
1242 self._SubsectionName = self._ValueList[0]
1243 if self._SubsectionName in self.DataType:
1244 self._SubsectionType = self.DataType[self._SubsectionName]
1245 else:
1246 self._SubsectionType = MODEL_UNKNOWN
1247
1248 def __RetrievePcdValue(self):
1249 Records = self._RawTable.Query(MODEL_PCD_FEATURE_FLAG, BelongsToItem=-1.0)
1250 for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
1251 Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1252 # Only use PCD whose value is straitforward (no macro and PCD)
1253 if self.SymbolPattern.findall(Value):
1254 continue
1255 Name = TokenSpaceGuid + '.' + PcdName
1256 # Don't use PCD with different values.
1257 if Name in self._Symbols and self._Symbols[Name] != Value:
1258 self._Symbols.pop(Name)
1259 continue
1260 self._Symbols[Name] = Value
1261
1262 Records = self._RawTable.Query(MODEL_PCD_FIXED_AT_BUILD, BelongsToItem=-1.0)
1263 for TokenSpaceGuid, PcdName, Value, Dummy2, Dummy3, ID, Line in Records:
1264 Value, DatumType, MaxDatumSize = AnalyzePcdData(Value)
1265 # Only use PCD whose value is straitforward (no macro and PCD)
1266 if self.SymbolPattern.findall(Value):
1267 continue
1268 Name = TokenSpaceGuid+'.'+PcdName
1269 # Don't use PCD with different values.
1270 if Name in self._Symbols and self._Symbols[Name] != Value:
1271 self._Symbols.pop(Name)
1272 continue
1273 self._Symbols[Name] = Value
1274
1275 def __ProcessDefine(self):
1276 if not self._Enabled:
1277 return
1278
1279 Type, Name, Value = self._ValueList
1280 Value = ReplaceMacro(Value, self._Macros, False)
1281 if self._ItemType == MODEL_META_DATA_DEFINE:
1282 if self._SectionType == MODEL_META_DATA_HEADER:
1283 self._FileLocalMacros[Name] = Value
1284 else:
1285 SectionDictKey = self._SectionType, self._Scope[0][0], self._Scope[0][1]
1286 if SectionDictKey not in self._SectionsMacroDict:
1287 self._SectionsMacroDict[SectionDictKey] = {}
1288 SectionLocalMacros = self._SectionsMacroDict[SectionDictKey]
1289 SectionLocalMacros[Name] = Value
1290 elif self._ItemType == MODEL_META_DATA_GLOBAL_DEFINE:
1291 GlobalData.gEdkGlobal[Name] = Value
1292
1293 #
1294 # Keyword in [Defines] section can be used as Macros
1295 #
1296 if (self._ItemType == MODEL_META_DATA_HEADER) and (self._SectionType == MODEL_META_DATA_HEADER):
1297 self._FileLocalMacros[Name] = Value
1298
1299 self._ValueList = [Type, Name, Value]
1300
1301 def __ProcessDirective(self):
1302 Result = None
1303 if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1304 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF]:
1305 Macros = self._Macros
1306 Macros.update(GlobalData.gGlobalDefines)
1307 try:
1308 Result = ValueExpression(self._ValueList[1], Macros)()
1309 except SymbolNotFound as Exc:
1310 EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1311 Result = False
1312 except WrnExpression as Excpt:
1313 #
1314 # Catch expression evaluation warning here. We need to report
1315 # the precise number of line and return the evaluation result
1316 #
1317 EdkLogger.warn('Parser', "Suspicious expression: %s" % str(Excpt),
1318 File=self._FileWithError, ExtraData=' '.join(self._ValueList),
1319 Line=self._LineIndex+1)
1320 Result = Excpt.result
1321 except BadExpression as Exc:
1322 EdkLogger.debug(EdkLogger.DEBUG_5, str(Exc), self._ValueList[1])
1323 Result = False
1324
1325 if self._ItemType in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1326 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1327 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1328 self._DirectiveStack.append(self._ItemType)
1329 if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IF:
1330 Result = bool(Result)
1331 else:
1332 Macro = self._ValueList[1]
1333 Macro = Macro[2:-1] if (Macro.startswith("$(") and Macro.endswith(")")) else Macro
1334 Result = Macro in self._Macros
1335 if self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF:
1336 Result = not Result
1337 self._DirectiveEvalStack.append(Result)
1338 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF:
1339 self._DirectiveStack.append(self._ItemType)
1340 self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1341 self._DirectiveEvalStack.append(bool(Result))
1342 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE:
1343 self._DirectiveStack[-1] = self._ItemType
1344 self._DirectiveEvalStack[-1] = not self._DirectiveEvalStack[-1]
1345 elif self._ItemType == MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF:
1346 # Back to the nearest !if/!ifdef/!ifndef
1347 while self._DirectiveStack:
1348 self._DirectiveEvalStack.pop()
1349 Directive = self._DirectiveStack.pop()
1350 if Directive in [MODEL_META_DATA_CONDITIONAL_STATEMENT_IF,
1351 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF,
1352 MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE,
1353 MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF]:
1354 break
1355 elif self._ItemType == MODEL_META_DATA_INCLUDE:
1356 # The included file must be relative to workspace or same directory as DSC file
1357 __IncludeMacros = {}
1358 #
1359 # Allow using system environment variables in path after !include
1360 #
1361 __IncludeMacros['WORKSPACE'] = GlobalData.gGlobalDefines['WORKSPACE']
1362 if "ECP_SOURCE" in GlobalData.gGlobalDefines.keys():
1363 __IncludeMacros['ECP_SOURCE'] = GlobalData.gGlobalDefines['ECP_SOURCE']
1364 #
1365 # During GenFds phase call DSC parser, will go into this branch.
1366 #
1367 elif "ECP_SOURCE" in GlobalData.gCommandLineDefines.keys():
1368 __IncludeMacros['ECP_SOURCE'] = GlobalData.gCommandLineDefines['ECP_SOURCE']
1369
1370 __IncludeMacros['EFI_SOURCE'] = GlobalData.gGlobalDefines['EFI_SOURCE']
1371 __IncludeMacros['EDK_SOURCE'] = GlobalData.gGlobalDefines['EDK_SOURCE']
1372 #
1373 # Allow using MACROs comes from [Defines] section to keep compatible.
1374 #
1375 __IncludeMacros.update(self._Macros)
1376
1377 IncludedFile = NormPath(ReplaceMacro(self._ValueList[1], __IncludeMacros, RaiseError=True))
1378 #
1379 # First search the include file under the same directory as DSC file
1380 #
1381 IncludedFile1 = PathClass(IncludedFile, self.MetaFile.Dir)
1382 ErrorCode, ErrorInfo1 = IncludedFile1.Validate()
1383 if ErrorCode != 0:
1384 #
1385 # Also search file under the WORKSPACE directory
1386 #
1387 IncludedFile1 = PathClass(IncludedFile, GlobalData.gWorkspace)
1388 ErrorCode, ErrorInfo2 = IncludedFile1.Validate()
1389 if ErrorCode != 0:
1390 EdkLogger.error('parser', ErrorCode, File=self._FileWithError,
1391 Line=self._LineIndex+1, ExtraData=ErrorInfo1 + "\n"+ ErrorInfo2)
1392
1393 self._FileWithError = IncludedFile1
1394
1395 IncludedFileTable = MetaFileStorage(self._Table.Cur, IncludedFile1, MODEL_FILE_DSC, True)
1396 Owner = self._Content[self._ContentIndex-1][0]
1397 Parser = DscParser(IncludedFile1, self._FileType, IncludedFileTable,
1398 Owner=Owner, From=Owner)
1399
1400 # set the parser status with current status
1401 Parser._SectionName = self._SectionName
1402 Parser._SectionType = self._SectionType
1403 Parser._Scope = self._Scope
1404 Parser._Enabled = self._Enabled
1405 # Parse the included file
1406 Parser.Start()
1407
1408 # update current status with sub-parser's status
1409 self._SectionName = Parser._SectionName
1410 self._SectionType = Parser._SectionType
1411 self._Scope = Parser._Scope
1412 self._Enabled = Parser._Enabled
1413
1414 # Insert all records in the table for the included file into dsc file table
1415 Records = IncludedFileTable.GetAll()
1416 if Records:
1417 self._Content[self._ContentIndex:self._ContentIndex] = Records
1418 self._Content.pop(self._ContentIndex-1)
1419 self._ValueList = None
1420 self._ContentIndex -= 1
1421
1422 def __ProcessSkuId(self):
1423 self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=True)
1424 for Value in self._ValueList]
1425
1426 def __ProcessLibraryInstance(self):
1427 self._ValueList = [ReplaceMacro(Value, self._Macros) for Value in self._ValueList]
1428
1429 def __ProcessLibraryClass(self):
1430 self._ValueList[1] = ReplaceMacro(self._ValueList[1], self._Macros, RaiseError=True)
1431
1432 def __ProcessPcd(self):
1433 ValueList = GetSplitValueList(self._ValueList[2])
1434 #
1435 # PCD value can be an expression
1436 #
1437 if len(ValueList) > 1 and ValueList[1] == TAB_VOID:
1438 PcdValue = ValueList[0]
1439 try:
1440 ValueList[0] = ValueExpression(PcdValue, self._Macros)(True)
1441 except WrnExpression as Value:
1442 ValueList[0] = Value.result
1443 else:
1444 PcdValue = ValueList[-1]
1445 try:
1446 ValueList[-1] = ValueExpression(PcdValue, self._Macros)(True)
1447 except WrnExpression as Value:
1448 ValueList[-1] = Value.result
1449
1450 if ValueList[-1] == 'True':
1451 ValueList[-1] = '1'
1452 if ValueList[-1] == 'False':
1453 ValueList[-1] = '0'
1454
1455 self._ValueList[2] = '|'.join(ValueList)
1456
1457 def __ProcessComponent(self):
1458 self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1459
1460 def __ProcessSourceOverridePath(self):
1461 self._ValueList[0] = ReplaceMacro(self._ValueList[0], self._Macros)
1462
1463 def __ProcessBuildOption(self):
1464 self._ValueList = [ReplaceMacro(Value, self._Macros, RaiseError=False)
1465 for Value in self._ValueList]
1466
1467 _SectionParser = {
1468 MODEL_META_DATA_HEADER : _DefineParser,
1469 MODEL_EFI_SKU_ID : _SkuIdParser,
1470 MODEL_EFI_LIBRARY_INSTANCE : _LibraryInstanceParser,
1471 MODEL_EFI_LIBRARY_CLASS : _LibraryClassParser,
1472 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
1473 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
1474 MODEL_PCD_FEATURE_FLAG : _PcdParser,
1475 MODEL_PCD_DYNAMIC_DEFAULT : _PcdParser,
1476 MODEL_PCD_DYNAMIC_HII : _PcdParser,
1477 MODEL_PCD_DYNAMIC_VPD : _PcdParser,
1478 MODEL_PCD_DYNAMIC_EX_DEFAULT : _PcdParser,
1479 MODEL_PCD_DYNAMIC_EX_HII : _PcdParser,
1480 MODEL_PCD_DYNAMIC_EX_VPD : _PcdParser,
1481 MODEL_META_DATA_COMPONENT : _ComponentParser,
1482 MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH : _CompponentSourceOverridePathParser,
1483 MODEL_META_DATA_BUILD_OPTION : _BuildOptionParser,
1484 MODEL_UNKNOWN : MetaFileParser._Skip,
1485 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
1486 MODEL_META_DATA_SECTION_HEADER : MetaFileParser._SectionHeaderParser,
1487 MODEL_META_DATA_SUBSECTION_HEADER : _SubsectionHeaderParser,
1488 }
1489
1490 _Macros = property(_GetMacros)
1491
1492 ## DEC file parser class
1493 #
1494 # @param FilePath The path of platform description file
1495 # @param FileType The raw data of DSC file
1496 # @param Table Database used to retrieve module/package information
1497 # @param Macros Macros used for replacement in file
1498 #
1499 class DecParser(MetaFileParser):
1500 # DEC file supported data types (one type per section)
1501 DataType = {
1502 TAB_DEC_DEFINES.upper() : MODEL_META_DATA_HEADER,
1503 TAB_DSC_DEFINES_DEFINE : MODEL_META_DATA_DEFINE,
1504 TAB_INCLUDES.upper() : MODEL_EFI_INCLUDE,
1505 TAB_LIBRARY_CLASSES.upper() : MODEL_EFI_LIBRARY_CLASS,
1506 TAB_GUIDS.upper() : MODEL_EFI_GUID,
1507 TAB_PPIS.upper() : MODEL_EFI_PPI,
1508 TAB_PROTOCOLS.upper() : MODEL_EFI_PROTOCOL,
1509 TAB_PCDS_FIXED_AT_BUILD_NULL.upper() : MODEL_PCD_FIXED_AT_BUILD,
1510 TAB_PCDS_PATCHABLE_IN_MODULE_NULL.upper() : MODEL_PCD_PATCHABLE_IN_MODULE,
1511 TAB_PCDS_FEATURE_FLAG_NULL.upper() : MODEL_PCD_FEATURE_FLAG,
1512 TAB_PCDS_DYNAMIC_NULL.upper() : MODEL_PCD_DYNAMIC,
1513 TAB_PCDS_DYNAMIC_EX_NULL.upper() : MODEL_PCD_DYNAMIC_EX,
1514 }
1515
1516 ## Constructor of DecParser
1517 #
1518 # Initialize object of DecParser
1519 #
1520 # @param FilePath The path of platform description file
1521 # @param FileType The raw data of DSC file
1522 # @param Table Database used to retrieve module/package information
1523 # @param Macros Macros used for replacement in file
1524 #
1525 def __init__(self, FilePath, FileType, Table):
1526 # prevent re-initialization
1527 if hasattr(self, "_Table"):
1528 return
1529 MetaFileParser.__init__(self, FilePath, FileType, Table)
1530 self._Comments = []
1531 self._Version = 0x00010005 # Only EDK2 dec file is supported
1532 self.TblFile = EccGlobalData.gDb.TblFile
1533 self.FileID = -1
1534
1535 ## Parser starter
1536 def Start(self):
1537 Content = ''
1538 try:
1539 Content = open(str(self.MetaFile), 'r').readlines()
1540 except:
1541 EdkLogger.error("Parser", FILE_READ_FAILURE, ExtraData=self.MetaFile)
1542
1543 #
1544 # Insert a record for file
1545 #
1546 Filename = NormPath(self.MetaFile)
1547 FileID = self.TblFile.GetFileId(Filename)
1548 if FileID:
1549 self.FileID = FileID
1550 else:
1551 self.FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_DEC)
1552
1553 for Index in range(0, len(Content)):
1554 Line, Comment = CleanString2(Content[Index])
1555 self._CurrentLine = Line
1556 self._LineIndex = Index
1557
1558 # save comment for later use
1559 if Comment:
1560 self._Comments.append((Comment, self._LineIndex+1))
1561 # skip empty line
1562 if Line == '':
1563 continue
1564
1565 # section header
1566 if Line[0] == TAB_SECTION_START and Line[-1] == TAB_SECTION_END:
1567 self._SectionHeaderParser()
1568 self._Comments = []
1569 continue
1570 elif len(self._SectionType) == 0:
1571 self._Comments = []
1572 continue
1573
1574 # section content
1575 self._ValueList = ['', '', '']
1576 self._SectionParser[self._SectionType[0]](self)
1577 if self._ValueList is None or self._ItemType == MODEL_META_DATA_DEFINE:
1578 self._ItemType = -1
1579 self._Comments = []
1580 continue
1581
1582 #
1583 # Model, Value1, Value2, Value3, Arch, BelongsToItem=-1, LineBegin=-1,
1584 # ColumnBegin=-1, LineEnd=-1, ColumnEnd=-1, FeatureFlag='', Enabled=-1
1585 #
1586 for Arch, ModuleType, Type in self._Scope:
1587 self._LastItem = self._Store(
1588 Type,
1589 self._ValueList[0],
1590 self._ValueList[1],
1591 self._ValueList[2],
1592 Arch,
1593 ModuleType,
1594 self._Owner[-1],
1595 self.FileID,
1596 self._LineIndex+1,
1597 -1,
1598 self._LineIndex+1,
1599 -1,
1600 0
1601 )
1602 for Comment, LineNo in self._Comments:
1603 self._Store(
1604 MODEL_META_DATA_COMMENT,
1605 Comment,
1606 self._ValueList[0],
1607 self._ValueList[1],
1608 Arch,
1609 ModuleType,
1610 self._LastItem,
1611 self.FileID,
1612 LineNo,
1613 -1,
1614 LineNo,
1615 -1,
1616 0
1617 )
1618 self._Comments = []
1619 self._Done()
1620
1621 def _GetApplicableSectionMacro(self):
1622 Macros = {}
1623 for S1, S2, SectionType in self._Scope:
1624 for Scope1, Scope2 in [("COMMON", "COMMON"), ("COMMON", S2), (S1, "COMMON"), (S1, S2)]:
1625 if (SectionType, Scope1, Scope2) in self._SectionsMacroDict:
1626 Macros.update(self._SectionsMacroDict[(SectionType, Scope1, Scope2)])
1627 return Macros
1628
1629 ## Section header parser
1630 #
1631 # The section header is always in following format:
1632 #
1633 # [section_name.arch<.platform|module_type>]
1634 #
1635 def _SectionHeaderParser(self):
1636 self._Scope = []
1637 self._SectionName = ''
1638 self._SectionType = []
1639 ArchList = set()
1640 for Item in GetSplitValueList(self._CurrentLine[1:-1], TAB_COMMA_SPLIT):
1641 if Item == '':
1642 continue
1643 ItemList = GetSplitValueList(Item, TAB_SPLIT)
1644
1645 # different types of PCD are permissible in one section
1646 self._SectionName = ItemList[0].upper()
1647 if self._SectionName in self.DataType:
1648 if self.DataType[self._SectionName] not in self._SectionType:
1649 self._SectionType.append(self.DataType[self._SectionName])
1650 else:
1651 EdkLogger.warn("Parser", "Unrecognized section", File=self.MetaFile,
1652 Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1653 continue
1654
1655 if MODEL_PCD_FEATURE_FLAG in self._SectionType and len(self._SectionType) > 1:
1656 EdkLogger.error(
1657 'Parser',
1658 FORMAT_INVALID,
1659 "%s must not be in the same section of other types of PCD" % TAB_PCDS_FEATURE_FLAG_NULL,
1660 File=self.MetaFile,
1661 Line=self._LineIndex+1,
1662 ExtraData=self._CurrentLine
1663 )
1664 # S1 is always Arch
1665 if len(ItemList) > 1:
1666 S1 = ItemList[1].upper()
1667 else:
1668 S1 = 'COMMON'
1669 ArchList.add(S1)
1670 # S2 may be Platform or ModuleType
1671 if len(ItemList) > 2:
1672 S2 = ItemList[2].upper()
1673 else:
1674 S2 = 'COMMON'
1675 if [S1, S2, self.DataType[self._SectionName]] not in self._Scope:
1676 self._Scope.append([S1, S2, self.DataType[self._SectionName]])
1677
1678 # 'COMMON' must not be used with specific ARCHs at the same section
1679 if 'COMMON' in ArchList and len(ArchList) > 1:
1680 EdkLogger.error('Parser', FORMAT_INVALID, "'common' ARCH must not be used with specific ARCHs",
1681 File=self.MetaFile, Line=self._LineIndex+1, ExtraData=self._CurrentLine)
1682
1683 ## [guids], [ppis] and [protocols] section parser
1684 @ParseMacro
1685 def _GuidParser(self):
1686 TokenList = GetSplitValueList(self._CurrentLine, TAB_EQUAL_SPLIT, 1)
1687 if len(TokenList) < 2:
1688 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name or value specified",
1689 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1690 File=self.MetaFile, Line=self._LineIndex+1)
1691 if TokenList[0] == '':
1692 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID name specified",
1693 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1694 File=self.MetaFile, Line=self._LineIndex+1)
1695 if TokenList[1] == '':
1696 EdkLogger.error('Parser', FORMAT_INVALID, "No GUID value specified",
1697 ExtraData=self._CurrentLine + " (<CName> = <GuidValueInCFormat>)",
1698 File=self.MetaFile, Line=self._LineIndex+1)
1699 if TokenList[1][0] != '{' or TokenList[1][-1] != '}' or GuidStructureStringToGuidString(TokenList[1]) == '':
1700 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1701 ExtraData=self._CurrentLine + \
1702 " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1703 File=self.MetaFile, Line=self._LineIndex+1)
1704 self._ValueList[0] = TokenList[0]
1705 #Parse the Guid value format
1706 GuidValueList = TokenList[1].strip(' {}').split(',')
1707 Index = 0
1708 HexList = []
1709 if len(GuidValueList) == 11:
1710 for GuidValue in GuidValueList:
1711 GuidValue = GuidValue.strip()
1712 if GuidValue.startswith('0x') or GuidValue.startswith('0X'):
1713 HexList.append('0x' + str(GuidValue[2:]))
1714 Index += 1
1715 continue
1716 else:
1717 if GuidValue.startswith('{'):
1718 GuidValue = GuidValue.lstrip(' {')
1719 HexList.append('0x' + str(GuidValue[2:]))
1720 Index += 1
1721 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])
1722 else:
1723 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid GUID value format",
1724 ExtraData=self._CurrentLine + \
1725 " (<CName> = <GuidValueInCFormat:{8,4,4,{2,2,2,2,2,2,2,2}}>)",
1726 File=self.MetaFile, Line=self._LineIndex+1)
1727 self._ValueList[0] = ''
1728
1729 ## PCD sections parser
1730 #
1731 # [PcdsFixedAtBuild]
1732 # [PcdsPatchableInModule]
1733 # [PcdsFeatureFlag]
1734 # [PcdsDynamicEx
1735 # [PcdsDynamic]
1736 #
1737 @ParseMacro
1738 def _PcdParser(self):
1739 TokenList = GetSplitValueList(self._CurrentLine, TAB_VALUE_SPLIT, 1)
1740 self._ValueList[0:1] = GetSplitValueList(TokenList[0], TAB_SPLIT)
1741 # check PCD information
1742 if self._ValueList[0] == '' or self._ValueList[1] == '':
1743 EdkLogger.error('Parser', FORMAT_INVALID, "No token space GUID or PCD name specified",
1744 ExtraData=self._CurrentLine + \
1745 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1746 File=self.MetaFile, Line=self._LineIndex+1)
1747 # check PCD datum information
1748 if len(TokenList) < 2 or TokenList[1] == '':
1749 EdkLogger.error('Parser', FORMAT_INVALID, "No PCD Datum information given",
1750 ExtraData=self._CurrentLine + \
1751 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1752 File=self.MetaFile, Line=self._LineIndex+1)
1753
1754
1755 ValueRe = re.compile(r'^\s*L?\".*\|.*\"')
1756 PtrValue = ValueRe.findall(TokenList[1])
1757
1758 # Has VOID* type string, may contain "|" character in the string.
1759 if len(PtrValue) != 0:
1760 ptrValueList = re.sub(ValueRe, '', TokenList[1])
1761 ValueList = GetSplitValueList(ptrValueList)
1762 ValueList[0] = PtrValue[0]
1763 else:
1764 ValueList = GetSplitValueList(TokenList[1])
1765
1766
1767 # check if there's enough datum information given
1768 if len(ValueList) != 3:
1769 EdkLogger.error('Parser', FORMAT_INVALID, "Invalid PCD Datum information given",
1770 ExtraData=self._CurrentLine + \
1771 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1772 File=self.MetaFile, Line=self._LineIndex+1)
1773 # check default value
1774 if ValueList[0] == '':
1775 EdkLogger.error('Parser', FORMAT_INVALID, "Missing DefaultValue in PCD Datum information",
1776 ExtraData=self._CurrentLine + \
1777 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1778 File=self.MetaFile, Line=self._LineIndex+1)
1779 # check datum type
1780 if ValueList[1] == '':
1781 EdkLogger.error('Parser', FORMAT_INVALID, "Missing DatumType in PCD Datum information",
1782 ExtraData=self._CurrentLine + \
1783 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1784 File=self.MetaFile, Line=self._LineIndex+1)
1785 # check token of the PCD
1786 if ValueList[2] == '':
1787 EdkLogger.error('Parser', FORMAT_INVALID, "Missing Token in PCD Datum information",
1788 ExtraData=self._CurrentLine + \
1789 " (<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>)",
1790 File=self.MetaFile, Line=self._LineIndex+1)
1791 # check format of default value against the datum type
1792 IsValid, Cause = CheckPcdDatum(ValueList[1], ValueList[0])
1793 if not IsValid:
1794 EdkLogger.error('Parser', FORMAT_INVALID, Cause, ExtraData=self._CurrentLine,
1795 File=self.MetaFile, Line=self._LineIndex+1)
1796
1797 if EccGlobalData.gConfig.UniCheckPCDInfo == '1' or EccGlobalData.gConfig.UniCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
1798 # check Description, Prompt information
1799 PatternDesc = re.compile('##\s*([\x21-\x7E\s]*)', re.S)
1800 PatternPrompt = re.compile('#\s+@Prompt\s+([\x21-\x7E\s]*)', re.S)
1801 Description = None
1802 Prompt = None
1803 # check @ValidRange, @ValidList and @Expression format valid
1804 ErrorCodeValid = '0x0 <= %s <= 0xFFFFFFFF'
1805 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]+)'
1806 PatternValidRng = re.compile('^' + '(NOT)?\s*' + PatternValidRangeIn + '$')
1807 for Comment in self._Comments:
1808 Comm = Comment[0].strip()
1809 if not Comm:
1810 continue
1811 if not Description:
1812 Description = PatternDesc.findall(Comm)
1813 if not Prompt:
1814 Prompt = PatternPrompt.findall(Comm)
1815 if Comm[0] == '#':
1816 ValidFormt = Comm.lstrip('#')
1817 ValidFormt = ValidFormt.lstrip()
1818 if ValidFormt[0:11] == '@ValidRange':
1819 ValidFormt = ValidFormt[11:]
1820 ValidFormt = ValidFormt.lstrip()
1821 try:
1822 ErrorCode, Expression = ValidFormt.split('|', 1)
1823 except ValueError:
1824 ErrorCode = '0x0'
1825 Expression = ValidFormt
1826 ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1827 try:
1828 if not eval(ErrorCodeValid % ErrorCode):
1829 EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1830 except:
1831 EdkLogger.warn('Parser', '@ValidRange ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1832 if not PatternValidRng.search(Expression):
1833 EdkLogger.warn('Parser', '@ValidRange Expression(%s) of PCD %s is incorrect format.' % (Expression, TokenList[0]))
1834 if ValidFormt[0:10] == '@ValidList':
1835 ValidFormt = ValidFormt[10:]
1836 ValidFormt = ValidFormt.lstrip()
1837 try:
1838 ErrorCode, Expression = ValidFormt.split('|', 1)
1839 except ValueError:
1840 ErrorCode = '0x0'
1841 Expression = ValidFormt
1842 ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1843 try:
1844 if not eval(ErrorCodeValid % ErrorCode):
1845 EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1846 except:
1847 EdkLogger.warn('Parser', '@ValidList ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1848 Values = Expression.split(',')
1849 for Value in Values:
1850 Value = Value.strip()
1851 try:
1852 eval(Value)
1853 except:
1854 EdkLogger.warn('Parser', '@ValidList Expression of PCD %s include a invalid value(%s).' % (TokenList[0], Value))
1855 break
1856 if ValidFormt[0:11] == '@Expression':
1857 ValidFormt = ValidFormt[11:]
1858 ValidFormt = ValidFormt.lstrip()
1859 try:
1860 ErrorCode, Expression = ValidFormt.split('|', 1)
1861 except ValueError:
1862 ErrorCode = '0x0'
1863 Expression = ValidFormt
1864 ErrorCode, Expression = ErrorCode.strip(), Expression.strip()
1865 try:
1866 if not eval(ErrorCodeValid % ErrorCode):
1867 EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1868 except:
1869 EdkLogger.warn('Parser', '@Expression ErrorCode(%s) of PCD %s is not valid UINT32 value.' % (ErrorCode, TokenList[0]))
1870 if not Expression:
1871 EdkLogger.warn('Parser', '@Expression Expression of PCD %s is incorrect format.' % TokenList[0])
1872 if not Description:
1873 EdkLogger.warn('Parser', 'PCD %s Description information is not provided.' % TokenList[0])
1874 if not Prompt:
1875 EdkLogger.warn('Parser', 'PCD %s Prompt information is not provided.' % TokenList[0])
1876 # check Description, Prompt localization information
1877 if self._UniObj:
1878 self._UniObj.CheckPcdInfo(TokenList[0])
1879
1880 if ValueList[0] in ['True', 'true', 'TRUE']:
1881 ValueList[0] = '1'
1882 elif ValueList[0] in ['False', 'false', 'FALSE']:
1883 ValueList[0] = '0'
1884
1885 self._ValueList[2] = ValueList[0].strip() + '|' + ValueList[1].strip() + '|' + ValueList[2].strip()
1886
1887 _SectionParser = {
1888 MODEL_META_DATA_HEADER : MetaFileParser._DefineParser,
1889 MODEL_EFI_INCLUDE : MetaFileParser._PathParser,
1890 MODEL_EFI_LIBRARY_CLASS : MetaFileParser._PathParser,
1891 MODEL_EFI_GUID : _GuidParser,
1892 MODEL_EFI_PPI : _GuidParser,
1893 MODEL_EFI_PROTOCOL : _GuidParser,
1894 MODEL_PCD_FIXED_AT_BUILD : _PcdParser,
1895 MODEL_PCD_PATCHABLE_IN_MODULE : _PcdParser,
1896 MODEL_PCD_FEATURE_FLAG : _PcdParser,
1897 MODEL_PCD_DYNAMIC : _PcdParser,
1898 MODEL_PCD_DYNAMIC_EX : _PcdParser,
1899 MODEL_UNKNOWN : MetaFileParser._Skip,
1900 MODEL_META_DATA_USER_EXTENSION : MetaFileParser._Skip,
1901 }
1902
1903
1904 ## Fdf
1905 #
1906 # This class defined the structure used in Fdf object
1907 #
1908 # @param Filename: Input value for Ffilename of Fdf file, default is None
1909 # @param WorkspaceDir: Input value for current workspace directory, default is None
1910 #
1911 class Fdf(object):
1912 def __init__(self, Filename = None, IsToDatabase = False, WorkspaceDir = None, Database = None):
1913 self.WorkspaceDir = WorkspaceDir
1914 self.IsToDatabase = IsToDatabase
1915
1916 self.Cur = Database.Cur
1917 self.TblFile = Database.TblFile
1918 self.TblFdf = Database.TblFdf
1919 self.FileID = -1
1920 self.FileList = {}
1921
1922 #
1923 # Load Fdf file if filename is not None
1924 #
1925 if Filename is not None:
1926 try:
1927 self.LoadFdfFile(Filename)
1928 except Exception:
1929 pass
1930
1931 #
1932 # Insert a FDF file record into database
1933 #
1934 def InsertFile(self, Filename):
1935 FileID = -1
1936 Filename = NormPath(Filename)
1937 if Filename not in self.FileList:
1938 FileID = self.TblFile.InsertFile(Filename, MODEL_FILE_FDF)
1939 self.FileList[Filename] = FileID
1940
1941 return self.FileList[Filename]
1942
1943
1944 ## Load Fdf file
1945 #
1946 # Load the file if it exists
1947 #
1948 # @param Filename: Input value for filename of Fdf file
1949 #
1950 def LoadFdfFile(self, Filename):
1951 FileList = []
1952 #
1953 # Parse Fdf file
1954 #
1955 Filename = NormPath(Filename)
1956 Fdf = FdfParser(Filename)
1957 Fdf.ParseFile()
1958
1959 #
1960 # Insert inf file and pcd information
1961 #
1962 if self.IsToDatabase:
1963 (Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled) = \
1964 (0, '', '', '', 'COMMON', 'COMMON', -1, -1, -1, -1, -1, -1, 0)
1965 for Index in range(0, len(Fdf.Profile.PcdDict)):
1966 pass
1967 for Key in Fdf.Profile.PcdDict.keys():
1968 Model = MODEL_PCD
1969 Value1 = Key[1]
1970 Value2 = Key[0]
1971 FileName = Fdf.Profile.PcdFileLineDict[Key][0]
1972 StartLine = Fdf.Profile.PcdFileLineDict[Key][1]
1973 BelongsToFile = self.InsertFile(FileName)
1974 self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1975 for Index in range(0, len(Fdf.Profile.InfList)):
1976 Model = MODEL_META_DATA_COMPONENT
1977 Value1 = Fdf.Profile.InfList[Index]
1978 Value2 = ''
1979 FileName = Fdf.Profile.InfFileLineList[Index][0]
1980 StartLine = Fdf.Profile.InfFileLineList[Index][1]
1981 BelongsToFile = self.InsertFile(FileName)
1982 self.TblFdf.Insert(Model, Value1, Value2, Value3, Scope1, Scope2, BelongsToItem, BelongsToFile, StartLine, StartColumn, EndLine, EndColumn, Enabled)
1983
1984 class UniParser(object):
1985 # IsExtraUni defined the UNI file is Module UNI or extra Module UNI
1986 # IsModuleUni defined the UNI file is Module UNI or Package UNI
1987 def __init__(self, FilePath, IsExtraUni=False, IsModuleUni=True):
1988 self.FilePath = FilePath
1989 self.FileName = os.path.basename(FilePath)
1990 self.IsExtraUni = IsExtraUni
1991 self.IsModuleUni = IsModuleUni
1992 self.FileIn = None
1993 self.Missing = []
1994 self.__read()
1995
1996 def __read(self):
1997 try:
1998 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_8').read()
1999 except UnicodeError:
2000 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16').read()
2001 except UnicodeError:
2002 self.FileIn = CodecOpenLongFilePath(self.FilePath, Mode='rb', Encoding='utf_16_le').read()
2003 except IOError:
2004 self.FileIn = ""
2005
2006 def Start(self):
2007 if self.IsModuleUni:
2008 if self.IsExtraUni:
2009 ModuleName = self.CheckKeyValid('STR_PROPERTIES_MODULE_NAME')
2010 self.PrintLog('STR_PROPERTIES_MODULE_NAME', ModuleName)
2011 else:
2012 ModuleAbstract = self.CheckKeyValid('STR_MODULE_ABSTRACT')
2013 self.PrintLog('STR_MODULE_ABSTRACT', ModuleAbstract)
2014 ModuleDescription = self.CheckKeyValid('STR_MODULE_DESCRIPTION')
2015 self.PrintLog('STR_MODULE_DESCRIPTION', ModuleDescription)
2016 else:
2017 if self.IsExtraUni:
2018 PackageName = self.CheckKeyValid('STR_PROPERTIES_PACKAGE_NAME')
2019 self.PrintLog('STR_PROPERTIES_PACKAGE_NAME', PackageName)
2020 else:
2021 PackageAbstract = self.CheckKeyValid('STR_PACKAGE_ABSTRACT')
2022 self.PrintLog('STR_PACKAGE_ABSTRACT', PackageAbstract)
2023 PackageDescription = self.CheckKeyValid('STR_PACKAGE_DESCRIPTION')
2024 self.PrintLog('STR_PACKAGE_DESCRIPTION', PackageDescription)
2025
2026 def CheckKeyValid(self, Key, Contents=None):
2027 if not Contents:
2028 Contents = self.FileIn
2029 KeyPattern = re.compile('#string\s+%s\s+.*?#language.*?".*?"' % Key, re.S)
2030 if KeyPattern.search(Contents):
2031 return True
2032 return False
2033
2034 def CheckPcdInfo(self, PcdCName):
2035 PromptKey = 'STR_%s_PROMPT' % PcdCName.replace('.', '_')
2036 PcdPrompt = self.CheckKeyValid(PromptKey)
2037 self.PrintLog(PromptKey, PcdPrompt)
2038 HelpKey = 'STR_%s_HELP' % PcdCName.replace('.', '_')
2039 PcdHelp = self.CheckKeyValid(HelpKey)
2040 self.PrintLog(HelpKey, PcdHelp)
2041
2042 def PrintLog(self, Key, Value):
2043 if not Value and Key not in self.Missing:
2044 Msg = '%s is missing in the %s file.' % (Key, self.FileName)
2045 EdkLogger.warn('Parser', Msg)
2046 EccGlobalData.gDb.TblReport.Insert(EccToolError.ERROR_GENERAL_CHECK_UNI_HELP_INFO, OtherMsg=Msg, BelongsToTable='File', BelongsToItem=-2)
2047 self.Missing.append(Key)
2048
2049 ##
2050 #
2051 # This acts like the main() function for the script, unless it is 'import'ed into another
2052 # script.
2053 #
2054 if __name__ == '__main__':
2055 pass
2056