1## @file
2# This file is used to define common parsing related functions used in parsing
3# INF/DEC/DSC process
4#
5# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
6#
7# This program and the accompanying materials are licensed and made available
8# under the terms and conditions of the BSD License which accompanies this
9# distribution. The full text of the license may be found at
10# http://opensource.org/licenses/bsd-license.php
11#
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14#
15
16'''
17Parsing
18'''
19
20##
21# Import Modules
22#
23import os.path
24import re
25
26from Library.String import RaiseParserError
27from Library.String import GetSplitValueList
28from Library.String import CheckFileType
29from Library.String import CheckFileExist
30from Library.String import CleanString
31from Library.String import NormPath
32
33from Logger.ToolError import FILE_NOT_FOUND
34from Logger.ToolError import FatalError
35from Logger.ToolError import FORMAT_INVALID
36
37from Library import DataType
38
39from Library.Misc import GuidStructureStringToGuidString
40from Library.Misc import CheckGuidRegFormat
41from Logger import StringTable as ST
42import Logger.Log as Logger
43
44from Parser.DecParser import Dec
45import GlobalData
46
47gPKG_INFO_DICT = {}
48
49## GetBuildOption
50#
51# Parse a string with format "[<Family>:]<ToolFlag>=Flag"
52# Return (Family, ToolFlag, Flag)
53#
54# @param String:  String with BuildOption statement
55# @param File:    The file which defines build option, used in error report
56#
57def GetBuildOption(String, File, LineNo= -1):
58    (Family, ToolChain, Flag) = ('', '', '')
59    if String.find(DataType.TAB_EQUAL_SPLIT) < 0:
60        RaiseParserError(String, 'BuildOptions', File, \
61                         '[<Family>:]<ToolFlag>=Flag', LineNo)
62    else:
63        List = GetSplitValueList(String, DataType.TAB_EQUAL_SPLIT, MaxSplit=1)
64        if List[0].find(':') > -1:
65            Family = List[0][ : List[0].find(':')].strip()
66            ToolChain = List[0][List[0].find(':') + 1 : ].strip()
67        else:
68            ToolChain = List[0].strip()
69        Flag = List[1].strip()
70    return (Family, ToolChain, Flag)
71
72## Get Library Class
73#
74# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
75#
76# @param Item:           String as <LibraryClassKeyWord>|<LibraryInstance>
77# @param ContainerFile:  The file which describes the library class, used for
78#                        error report
79#
80def GetLibraryClass(Item, ContainerFile, WorkspaceDir, LineNo= -1):
81    List = GetSplitValueList(Item[0])
82    SupMod = DataType.SUP_MODULE_LIST_STRING
83    if len(List) != 2:
84        RaiseParserError(Item[0], 'LibraryClasses', ContainerFile, \
85                         '<LibraryClassKeyWord>|<LibraryInstance>')
86    else:
87        CheckFileType(List[1], '.Inf', ContainerFile, \
88                      'library class instance', Item[0], LineNo)
89        CheckFileExist(WorkspaceDir, List[1], ContainerFile, \
90                       'LibraryClasses', Item[0], LineNo)
91        if Item[1] != '':
92            SupMod = Item[1]
93
94    return (List[0], List[1], SupMod)
95
96## Get Library Class
97#
98# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>]
99# [|<TokenSpaceGuidCName>.<PcdCName>]
100#
101# @param Item:           String as <LibraryClassKeyWord>|<LibraryInstance>
102# @param ContainerFile:  The file which describes the library class, used for
103#                        error report
104#
105def GetLibraryClassOfInf(Item, ContainerFile, WorkspaceDir, LineNo= -1):
106    ItemList = GetSplitValueList((Item[0] + DataType.TAB_VALUE_SPLIT * 2))
107    SupMod = DataType.SUP_MODULE_LIST_STRING
108
109    if len(ItemList) > 5:
110        RaiseParserError\
111        (Item[0], 'LibraryClasses', ContainerFile, \
112         '<LibraryClassKeyWord>[|<LibraryInstance>]\
113         [|<TokenSpaceGuidCName>.<PcdCName>]')
114    else:
115        CheckFileType(ItemList[1], '.Inf', ContainerFile, 'LibraryClasses', \
116                      Item[0], LineNo)
117        CheckFileExist(WorkspaceDir, ItemList[1], ContainerFile, \
118                       'LibraryClasses', Item[0], LineNo)
119        if ItemList[2] != '':
120            CheckPcdTokenInfo(ItemList[2], 'LibraryClasses', \
121                              ContainerFile, LineNo)
122        if Item[1] != '':
123            SupMod = Item[1]
124
125    return (ItemList[0], ItemList[1], ItemList[2], SupMod)
126
127## CheckPcdTokenInfo
128#
129# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>
130#
131# @param TokenInfoString:  String to be checked
132# @param Section:          Used for error report
133# @param File:             Used for error report
134#
135def CheckPcdTokenInfo(TokenInfoString, Section, File, LineNo= -1):
136    Format = '<TokenSpaceGuidCName>.<PcdCName>'
137    if TokenInfoString != '' and TokenInfoString != None:
138        TokenInfoList = GetSplitValueList(TokenInfoString, DataType.TAB_SPLIT)
139        if len(TokenInfoList) == 2:
140            return True
141
142    RaiseParserError(TokenInfoString, Section, File, Format, LineNo)
143
144## Get Pcd
145#
146# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>
147# [|<Type>|<MaximumDatumSize>]
148#
149# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|
150#                        <Value>[|<Type>|<MaximumDatumSize>]
151# @param ContainerFile:  The file which describes the pcd, used for error
152#                        report
153
154#
155def GetPcd(Item, Type, ContainerFile, LineNo= -1):
156    TokenGuid, TokenName, Value, MaximumDatumSize, Token = '', '', '', '', ''
157    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
158
159    if len(List) < 4 or len(List) > 6:
160        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
161                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\
162                         [|<Type>|<MaximumDatumSize>]', LineNo)
163    else:
164        Value = List[1]
165        MaximumDatumSize = List[2]
166        Token = List[3]
167
168    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
169        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
170
171    return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type)
172
173## Get FeatureFlagPcd
174#
175# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
176#
177# @param Item:           String as <PcdTokenSpaceGuidCName>
178#                        .<TokenCName>|TRUE/FALSE
179# @param ContainerFile:  The file which describes the pcd, used for error
180#                        report
181#
182def GetFeatureFlagPcd(Item, Type, ContainerFile, LineNo= -1):
183    TokenGuid, TokenName, Value = '', '', ''
184    List = GetSplitValueList(Item)
185    if len(List) != 2:
186        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
187                         '<PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE', \
188                         LineNo)
189    else:
190        Value = List[1]
191    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
192        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
193
194    return (TokenName, TokenGuid, Value, Type)
195
196## Get DynamicDefaultPcd
197#
198# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>
199# |<Value>[|<DatumTyp>[|<MaxDatumSize>]]
200#
201# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|
202#                        TRUE/FALSE
203# @param ContainerFile:  The file which describes the pcd, used for error
204#                        report
205#
206def GetDynamicDefaultPcd(Item, Type, ContainerFile, LineNo= -1):
207    TokenGuid, TokenName, Value, DatumTyp, MaxDatumSize = '', '', '', '', ''
208    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
209    if len(List) < 4 or len(List) > 8:
210        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
211                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<Value>\
212                         [|<DatumTyp>[|<MaxDatumSize>]]', LineNo)
213    else:
214        Value = List[1]
215        DatumTyp = List[2]
216        MaxDatumSize = List[3]
217    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
218        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
219
220    return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type)
221
222## Get DynamicHiiPcd
223#
224# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|
225# <VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
226#
227# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>|
228#                        TRUE/FALSE
229# @param ContainerFile:  The file which describes the pcd, used for error
230#                        report
231#
232def GetDynamicHiiPcd(Item, Type, ContainerFile, LineNo= -1):
233    TokenGuid, TokenName, List1, List2, List3, List4, List5 = \
234    '', '', '', '', '', '', ''
235    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT * 2)
236    if len(List) < 6 or len(List) > 8:
237        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
238                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<String>|\
239                         <VariableGuidCName>|<VariableOffset>[|<DefaultValue>\
240                         [|<MaximumDatumSize>]]', LineNo)
241    else:
242        List1, List2, List3, List4, List5 = \
243        List[1], List[2], List[3], List[4], List[5]
244    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
245        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
246
247    return (TokenName, TokenGuid, List1, List2, List3, List4, List5, Type)
248
249## Get DynamicVpdPcd
250#
251# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|
252# <VpdOffset>[|<MaximumDatumSize>]
253#
254# @param Item:           String as <PcdTokenSpaceGuidCName>.<TokenCName>
255#                        |TRUE/FALSE
256# @param ContainerFile:  The file which describes the pcd, used for error
257#                        report
258#
259def GetDynamicVpdPcd(Item, Type, ContainerFile, LineNo= -1):
260    TokenGuid, TokenName, List1, List2 = '', '', '', ''
261    List = GetSplitValueList(Item + DataType.TAB_VALUE_SPLIT)
262    if len(List) < 3 or len(List) > 4:
263        RaiseParserError(Item, 'Pcds' + Type, ContainerFile, \
264                         '<PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>\
265                         [|<MaximumDatumSize>]', LineNo)
266    else:
267        List1, List2 = List[1], List[2]
268    if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
269        (TokenGuid, TokenName) = GetSplitValueList(List[0], DataType.TAB_SPLIT)
270
271    return (TokenName, TokenGuid, List1, List2, Type)
272
273## GetComponent
274#
275# Parse block of the components defined in dsc file
276# Set KeyValues as [ ['component name', [lib1, lib2, lib3],
277# [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
278#
279# @param Lines:             The content to be parsed
280# @param KeyValues:         To store data after parsing
281#
282def GetComponent(Lines, KeyValues):
283    (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
284     FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \
285     FindPcdsDynamicEx) = (False, False, False, False, False, False, False, \
286                           False)
287    ListItem = None
288    LibraryClassItem = []
289    BuildOption = []
290    Pcd = []
291
292    for Line in Lines:
293        Line = Line[0]
294        #
295        # Ignore !include statement
296        #
297        if Line.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1 or \
298        Line.upper().find(DataType.TAB_DEFINE + ' ') > -1:
299            continue
300
301        if FindBlock == False:
302            ListItem = Line
303            #
304            # find '{' at line tail
305            #
306            if Line.endswith('{'):
307                FindBlock = True
308                ListItem = CleanString(Line.rsplit('{', 1)[0], \
309                                       DataType.TAB_COMMENT_SPLIT)
310
311        #
312        # Parse a block content
313        #
314        if FindBlock:
315            if Line.find('<LibraryClasses>') != -1:
316                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
317                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
318                 FindPcdsDynamic, FindPcdsDynamicEx) = \
319                 (True, False, False, False, False, False, False)
320                continue
321            if Line.find('<BuildOptions>') != -1:
322                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
323                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
324                 FindPcdsDynamic, FindPcdsDynamicEx) = \
325                 (False, True, False, False, False, False, False)
326                continue
327            if Line.find('<PcdsFeatureFlag>') != -1:
328                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
329                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
330                 FindPcdsDynamic, FindPcdsDynamicEx) = \
331                 (False, False, True, False, False, False, False)
332                continue
333            if Line.find('<PcdsPatchableInModule>') != -1:
334                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
335                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
336                 FindPcdsDynamic, FindPcdsDynamicEx) = \
337                 (False, False, False, True, False, False, False)
338                continue
339            if Line.find('<PcdsFixedAtBuild>') != -1:
340                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
341                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
342                 FindPcdsDynamic, FindPcdsDynamicEx) = \
343                 (False, False, False, False, True, False, False)
344                continue
345            if Line.find('<PcdsDynamic>') != -1:
346                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
347                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
348                 FindPcdsDynamic, FindPcdsDynamicEx) = \
349                 (False, False, False, False, False, True, False)
350                continue
351            if Line.find('<PcdsDynamicEx>') != -1:
352                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
353                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
354                 FindPcdsDynamic, FindPcdsDynamicEx) = \
355                 (False, False, False, False, False, False, True)
356                continue
357            if Line.endswith('}'):
358                #
359                # find '}' at line tail
360                #
361                KeyValues.append([ListItem, LibraryClassItem, \
362                                  BuildOption, Pcd])
363                (FindBlock, FindLibraryClass, FindBuildOption, \
364                 FindPcdsFeatureFlag, FindPcdsPatchableInModule, \
365                 FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \
366                 (False, False, False, False, False, False, False, False)
367                LibraryClassItem, BuildOption, Pcd = [], [], []
368                continue
369
370        if FindBlock:
371            if FindLibraryClass:
372                LibraryClassItem.append(Line)
373            elif FindBuildOption:
374                BuildOption.append(Line)
375            elif FindPcdsFeatureFlag:
376                Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG_NULL, Line))
377            elif FindPcdsPatchableInModule:
378                Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE_NULL, Line))
379            elif FindPcdsFixedAtBuild:
380                Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD_NULL, Line))
381            elif FindPcdsDynamic:
382                Pcd.append((DataType.TAB_PCDS_DYNAMIC_DEFAULT_NULL, Line))
383            elif FindPcdsDynamicEx:
384                Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL, Line))
385        else:
386            KeyValues.append([ListItem, [], [], []])
387
388    return True
389
390## GetExec
391#
392# Parse a string with format "InfFilename [EXEC = ExecFilename]"
393# Return (InfFilename, ExecFilename)
394#
395# @param String:  String with EXEC statement
396#
397def GetExec(String):
398    InfFilename = ''
399    ExecFilename = ''
400    if String.find('EXEC') > -1:
401        InfFilename = String[ : String.find('EXEC')].strip()
402        ExecFilename = String[String.find('EXEC') + len('EXEC') : ].strip()
403    else:
404        InfFilename = String.strip()
405
406    return (InfFilename, ExecFilename)
407
408## GetComponents
409#
410# Parse block of the components defined in dsc file
411# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3],
412# [pcd1, pcd2, pcd3]], ...]
413#
414# @param Lines:             The content to be parsed
415# @param Key:               Reserved
416# @param KeyValues:         To store data after parsing
417# @param CommentCharacter:  Comment char, used to ignore comment content
418#
419# @retval True Get component successfully
420#
421def GetComponents(Lines, KeyValues, CommentCharacter):
422    if Lines.find(DataType.TAB_SECTION_END) > -1:
423        Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
424    (FindBlock, FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
425     FindPcdsPatchableInModule, FindPcdsFixedAtBuild, FindPcdsDynamic, \
426     FindPcdsDynamicEx) = \
427     (False, False, False, False, False, False, False, False)
428    ListItem = None
429    LibraryClassItem = []
430    BuildOption = []
431    Pcd = []
432
433    LineList = Lines.split('\n')
434    for Line in LineList:
435        Line = CleanString(Line, CommentCharacter)
436        if Line == None or Line == '':
437            continue
438
439        if FindBlock == False:
440            ListItem = Line
441            #
442            # find '{' at line tail
443            #
444            if Line.endswith('{'):
445                FindBlock = True
446                ListItem = CleanString(Line.rsplit('{', 1)[0], CommentCharacter)
447
448        #
449        # Parse a block content
450        #
451        if FindBlock:
452            if Line.find('<LibraryClasses>') != -1:
453                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
454                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
455                 FindPcdsDynamic, FindPcdsDynamicEx) = \
456                 (True, False, False, False, False, False, False)
457                continue
458            if Line.find('<BuildOptions>') != -1:
459                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
460                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
461                 FindPcdsDynamic, FindPcdsDynamicEx) = \
462                 (False, True, False, False, False, False, False)
463                continue
464            if Line.find('<PcdsFeatureFlag>') != -1:
465                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
466                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
467                 FindPcdsDynamic, FindPcdsDynamicEx) = \
468                 (False, False, True, False, False, False, False)
469                continue
470            if Line.find('<PcdsPatchableInModule>') != -1:
471                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
472                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
473                 FindPcdsDynamic, FindPcdsDynamicEx) = \
474                 (False, False, False, True, False, False, False)
475                continue
476            if Line.find('<PcdsFixedAtBuild>') != -1:
477                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
478                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
479                 FindPcdsDynamic, FindPcdsDynamicEx) = \
480                 (False, False, False, False, True, False, False)
481                continue
482            if Line.find('<PcdsDynamic>') != -1:
483                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
484                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
485                 FindPcdsDynamic, FindPcdsDynamicEx) = \
486                 (False, False, False, False, False, True, False)
487                continue
488            if Line.find('<PcdsDynamicEx>') != -1:
489                (FindLibraryClass, FindBuildOption, FindPcdsFeatureFlag, \
490                 FindPcdsPatchableInModule, FindPcdsFixedAtBuild, \
491                 FindPcdsDynamic, FindPcdsDynamicEx) = \
492                 (False, False, False, False, False, False, True)
493                continue
494            if Line.endswith('}'):
495                #
496                # find '}' at line tail
497                #
498                KeyValues.append([ListItem, LibraryClassItem, BuildOption, \
499                                  Pcd])
500                (FindBlock, FindLibraryClass, FindBuildOption, \
501                 FindPcdsFeatureFlag, FindPcdsPatchableInModule, \
502                 FindPcdsFixedAtBuild, FindPcdsDynamic, FindPcdsDynamicEx) = \
503                 (False, False, False, False, False, False, False, False)
504                LibraryClassItem, BuildOption, Pcd = [], [], []
505                continue
506
507        if FindBlock:
508            if FindLibraryClass:
509                LibraryClassItem.append(Line)
510            elif FindBuildOption:
511                BuildOption.append(Line)
512            elif FindPcdsFeatureFlag:
513                Pcd.append((DataType.TAB_PCDS_FEATURE_FLAG, Line))
514            elif FindPcdsPatchableInModule:
515                Pcd.append((DataType.TAB_PCDS_PATCHABLE_IN_MODULE, Line))
516            elif FindPcdsFixedAtBuild:
517                Pcd.append((DataType.TAB_PCDS_FIXED_AT_BUILD, Line))
518            elif FindPcdsDynamic:
519                Pcd.append((DataType.TAB_PCDS_DYNAMIC, Line))
520            elif FindPcdsDynamicEx:
521                Pcd.append((DataType.TAB_PCDS_DYNAMIC_EX, Line))
522        else:
523            KeyValues.append([ListItem, [], [], []])
524
525    return True
526
527## Get Source
528#
529# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>
530# [|<PcdFeatureFlag>]]]]
531#
532# @param Item:           String as <Filename>[|<Family>[|<TagName>[|<ToolCode>
533#                        [|<PcdFeatureFlag>]]]]
534# @param ContainerFile:  The file which describes the library class, used
535#                        for error report
536#
537def GetSource(Item, ContainerFile, FileRelativePath, LineNo= -1):
538    ItemNew = Item + DataType.TAB_VALUE_SPLIT * 4
539    List = GetSplitValueList(ItemNew)
540    if len(List) < 5 or len(List) > 9:
541        RaiseParserError(Item, 'Sources', ContainerFile, \
542                         '<Filename>[|<Family>[|<TagName>[|<ToolCode>\
543                         [|<PcdFeatureFlag>]]]]', LineNo)
544    List[0] = NormPath(List[0])
545    CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Sources', \
546                   Item, LineNo)
547    if List[4] != '':
548        CheckPcdTokenInfo(List[4], 'Sources', ContainerFile, LineNo)
549
550    return (List[0], List[1], List[2], List[3], List[4])
551
552## Get Binary
553#
554# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>
555# [|<PcdFeatureFlag>]]]]
556#
557# @param Item:           String as <Filename>[|<Family>[|<TagName>
558#                        [|<ToolCode>[|<PcdFeatureFlag>]]]]
559# @param ContainerFile:  The file which describes the library class,
560#                        used for error report
561#
562def GetBinary(Item, ContainerFile, LineNo= -1):
563    ItemNew = Item + DataType.TAB_VALUE_SPLIT
564    List = GetSplitValueList(ItemNew)
565    if len(List) < 3 or len(List) > 5:
566        RaiseParserError(Item, 'Binaries', ContainerFile, \
567                         "<FileType>|<Filename>[|<Target>\
568                         [|<TokenSpaceGuidCName>.<PcdCName>]]", LineNo)
569
570    if len(List) >= 4:
571        if List[3] != '':
572            CheckPcdTokenInfo(List[3], 'Binaries', ContainerFile, LineNo)
573        return (List[0], List[1], List[2], List[3])
574    elif len(List) == 3:
575        return (List[0], List[1], List[2], '')
576
577## Get Guids/Protocols/Ppis
578#
579# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
580#
581# @param Item:           String as <GuidCName>[|<PcdFeatureFlag>]
582# @param Type:           Type of parsing string
583# @param ContainerFile:  The file which describes the library class,
584#                        used for error report
585#
586def GetGuidsProtocolsPpisOfInf(Item):
587    ItemNew = Item + DataType.TAB_VALUE_SPLIT
588    List = GetSplitValueList(ItemNew)
589    return (List[0], List[1])
590
591## Get Guids/Protocols/Ppis
592#
593# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
594#
595# @param Item:           String as <GuidCName>=<GuidValue>
596# @param Type:           Type of parsing string
597# @param ContainerFile:  The file which describes the library class,
598# used for error report
599#
600def GetGuidsProtocolsPpisOfDec(Item, Type, ContainerFile, LineNo= -1):
601    List = GetSplitValueList(Item, DataType.TAB_EQUAL_SPLIT)
602    if len(List) != 2:
603        RaiseParserError(Item, Type, ContainerFile, '<CName>=<GuidValue>', \
604                         LineNo)
605    #
606    #convert C-Format Guid to Register Format
607    #
608    if List[1][0] == '{' and List[1][-1] == '}':
609        RegisterFormatGuid = GuidStructureStringToGuidString(List[1])
610        if RegisterFormatGuid == '':
611            RaiseParserError(Item, Type, ContainerFile, \
612                             'CFormat or RegisterFormat', LineNo)
613    else:
614        if CheckGuidRegFormat(List[1]):
615            RegisterFormatGuid = List[1]
616        else:
617            RaiseParserError(Item, Type, ContainerFile, \
618                             'CFormat or RegisterFormat', LineNo)
619
620    return (List[0], RegisterFormatGuid)
621
622## GetPackage
623#
624# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
625#
626# @param Item:           String as <PackagePath>[|<PcdFeatureFlag>]
627# @param Type:           Type of parsing string
628# @param ContainerFile:  The file which describes the library class,
629#                        used for error report
630#
631def GetPackage(Item, ContainerFile, FileRelativePath, LineNo= -1):
632    ItemNew = Item + DataType.TAB_VALUE_SPLIT
633    List = GetSplitValueList(ItemNew)
634    CheckFileType(List[0], '.Dec', ContainerFile, 'package', List[0], LineNo)
635    CheckFileExist(FileRelativePath, List[0], ContainerFile, 'Packages', \
636                   List[0], LineNo)
637    if List[1] != '':
638        CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo)
639
640    return (List[0], List[1])
641
642## Get Pcd Values of Inf
643#
644# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>]
645#
646# @param Item:  The string describes pcd
647# @param Type:  The type of Pcd
648# @param File:  The file which describes the pcd, used for error report
649#
650def GetPcdOfInf(Item, Type, File, LineNo):
651    Format = '<TokenSpaceGuidCName>.<PcdCName>[|<Value>]'
652    TokenGuid, TokenName, Value, InfType = '', '', '', ''
653
654    if Type == DataType.TAB_PCDS_FIXED_AT_BUILD:
655        InfType = DataType.TAB_INF_FIXED_PCD
656    elif Type == DataType.TAB_PCDS_PATCHABLE_IN_MODULE:
657        InfType = DataType.TAB_INF_PATCH_PCD
658    elif Type == DataType.TAB_PCDS_FEATURE_FLAG:
659        InfType = DataType.TAB_INF_FEATURE_PCD
660    elif Type == DataType.TAB_PCDS_DYNAMIC_EX:
661        InfType = DataType.TAB_INF_PCD_EX
662    elif Type == DataType.TAB_PCDS_DYNAMIC:
663        InfType = DataType.TAB_INF_PCD
664    List = GetSplitValueList(Item, DataType.TAB_VALUE_SPLIT, 1)
665    TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
666    if len(TokenInfo) != 2:
667        RaiseParserError(Item, InfType, File, Format, LineNo)
668    else:
669        TokenGuid = TokenInfo[0]
670        TokenName = TokenInfo[1]
671
672    if len(List) > 1:
673        Value = List[1]
674    else:
675        Value = None
676    return (TokenGuid, TokenName, Value, InfType)
677
678
679## Get Pcd Values of Dec
680#
681# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>
682# @param Item:  Pcd item
683# @param Type:  Pcd type
684# @param File:  Dec file
685# @param LineNo:  Line number
686#
687def GetPcdOfDec(Item, Type, File, LineNo= -1):
688    Format = '<TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token>'
689    TokenGuid, TokenName, Value, DatumType, Token = '', '', '', '', ''
690    List = GetSplitValueList(Item)
691    if len(List) != 4:
692        RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
693    else:
694        Value = List[1]
695        DatumType = List[2]
696        Token = List[3]
697    TokenInfo = GetSplitValueList(List[0], DataType.TAB_SPLIT)
698    if len(TokenInfo) != 2:
699        RaiseParserError(Item, 'Pcds' + Type, File, Format, LineNo)
700    else:
701        TokenGuid = TokenInfo[0]
702        TokenName = TokenInfo[1]
703
704    return (TokenGuid, TokenName, Value, DatumType, Token, Type)
705
706## Parse DEFINE statement
707#
708# Get DEFINE macros
709#
710# @param LineValue:  A DEFINE line value
711# @param StartLine:  A DEFINE start line
712# @param Table:      A table
713# @param FileID:     File ID
714# @param Filename:   File name
715# @param SectionName:  DEFINE section name
716# @param SectionModel:  DEFINE section model
717# @param Arch:   DEFINE arch
718#
719def ParseDefine(LineValue, StartLine, Table, FileID, SectionName, \
720                SectionModel, Arch):
721    Logger.Debug(Logger.DEBUG_2, ST.MSG_DEFINE_STATEMENT_FOUND % (LineValue, \
722                                                                  SectionName))
723    Define = \
724    GetSplitValueList(CleanString\
725                      (LineValue[LineValue.upper().\
726                                 find(DataType.TAB_DEFINE.upper() + ' ') + \
727                                 len(DataType.TAB_DEFINE + ' ') : ]), \
728                                 DataType.TAB_EQUAL_SPLIT, 1)
729    Table.Insert(DataType.MODEL_META_DATA_DEFINE, Define[0], Define[1], '', \
730                 '', '', Arch, SectionModel, FileID, StartLine, -1, \
731                 StartLine, -1, 0)
732
733## InsertSectionItems
734#
735# Insert item data of a section to a dict
736#
737# @param Model:   A model
738# @param CurrentSection:   Current section
739# @param SectionItemList:   Section item list
740# @param ArchList:   Arch list
741# @param ThirdList:   Third list
742# @param RecordSet:   Record set
743#
744def InsertSectionItems(Model, SectionItemList, ArchList, \
745                       ThirdList, RecordSet):
746    #
747    # Insert each item data of a section
748    #
749    for Index in range(0, len(ArchList)):
750        Arch = ArchList[Index]
751        Third = ThirdList[Index]
752        if Arch == '':
753            Arch = DataType.TAB_ARCH_COMMON
754
755        Records = RecordSet[Model]
756        for SectionItem in SectionItemList:
757            LineValue, StartLine, Comment = SectionItem[0], \
758            SectionItem[1], SectionItem[2]
759
760            Logger.Debug(4, ST.MSG_PARSING % LineValue)
761            #
762            # And then parse DEFINE statement
763            #
764            if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
765                continue
766            #
767            # At last parse other sections
768            #
769            IdNum = -1
770            Records.append([LineValue, Arch, StartLine, IdNum, Third, Comment])
771
772        if RecordSet != {}:
773            RecordSet[Model] = Records
774
775## GenMetaDatSectionItem
776#
777# @param Key:    A key
778# @param Value:  A value
779# @param List:   A list
780#
781def GenMetaDatSectionItem(Key, Value, List):
782    if Key not in List:
783        List[Key] = [Value]
784    else:
785        List[Key].append(Value)
786
787## GetPkgInfoFromDec
788#
789# get package name, guid, version info from dec files
790#
791# @param Path:   File path
792#
793def GetPkgInfoFromDec(Path):
794    PkgName = None
795    PkgGuid = None
796    PkgVersion = None
797
798    Path = Path.replace('\\', '/')
799
800    if not os.path.exists(Path):
801        Logger.Error("\nUPT", FILE_NOT_FOUND, File=Path)
802
803    if Path in gPKG_INFO_DICT:
804        return gPKG_INFO_DICT[Path]
805
806    try:
807        DecParser = None
808        if Path not in GlobalData.gPackageDict:
809            DecParser = Dec(Path)
810            GlobalData.gPackageDict[Path] = DecParser
811        else:
812            DecParser = GlobalData.gPackageDict[Path]
813
814        PkgName = DecParser.GetPackageName()
815        PkgGuid = DecParser.GetPackageGuid()
816        PkgVersion = DecParser.GetPackageVersion()
817        gPKG_INFO_DICT[Path] = (PkgName, PkgGuid, PkgVersion)
818        return PkgName, PkgGuid, PkgVersion
819    except FatalError:
820        return None, None, None
821
822
823## GetWorkspacePackage
824#
825# Get a list of workspace package information.
826#
827def GetWorkspacePackage():
828    DecFileList = []
829    WorkspaceDir = GlobalData.gWORKSPACE
830    for Root, Dirs, Files in os.walk(WorkspaceDir):
831        if 'CVS' in Dirs:
832            Dirs.remove('CVS')
833        if '.svn' in Dirs:
834            Dirs.remove('.svn')
835        for Dir in Dirs:
836            if Dir.startswith('.'):
837                Dirs.remove(Dir)
838        for FileSp in Files:
839            if FileSp.startswith('.'):
840                continue
841            Ext = os.path.splitext(FileSp)[1]
842            if Ext.lower() in ['.dec']:
843                DecFileList.append\
844                (os.path.normpath(os.path.join(Root, FileSp)))
845    #
846    # abstract package guid, version info from DecFile List
847    #
848    PkgList = []
849    for DecFile in DecFileList:
850        (PkgName, PkgGuid, PkgVersion) = GetPkgInfoFromDec(DecFile)
851        if PkgName and PkgGuid and PkgVersion:
852            PkgList.append((PkgName, PkgGuid, PkgVersion, DecFile))
853
854    return PkgList
855
856## GetWorkspaceModule
857#
858# Get a list of workspace modules.
859#
860def GetWorkspaceModule():
861    InfFileList = []
862    WorkspaceDir = GlobalData.gWORKSPACE
863    for Root, Dirs, Files in os.walk(WorkspaceDir):
864        if 'CVS' in Dirs:
865            Dirs.remove('CVS')
866        if '.svn' in Dirs:
867            Dirs.remove('.svn')
868        if 'Build' in Dirs:
869            Dirs.remove('Build')
870        for Dir in Dirs:
871            if Dir.startswith('.'):
872                Dirs.remove(Dir)
873        for FileSp in Files:
874            if FileSp.startswith('.'):
875                continue
876            Ext = os.path.splitext(FileSp)[1]
877            if Ext.lower() in ['.inf']:
878                InfFileList.append\
879                (os.path.normpath(os.path.join(Root, FileSp)))
880
881    return InfFileList
882
883## MacroParser used to parse macro definition
884#
885# @param Line:            The content contain linestring and line number
886# @param FileName:        The meta-file file name
887# @param SectionType:     Section for the Line belong to
888# @param FileLocalMacros: A list contain Macro defined in [Defines] section.
889#
890def MacroParser(Line, FileName, SectionType, FileLocalMacros):
891    MacroDefPattern = re.compile("^(DEFINE)[ \t]+")
892    LineContent = Line[0]
893    LineNo = Line[1]
894    Match = MacroDefPattern.match(LineContent)
895    if not Match:
896        #
897        # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
898        #
899        return None, None
900
901    TokenList = GetSplitValueList(LineContent[Match.end(1):], \
902                                  DataType.TAB_EQUAL_SPLIT, 1)
903    #
904    # Syntax check
905    #
906    if not TokenList[0]:
907        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACRONAME_NOGIVEN,
908                        ExtraData=LineContent, File=FileName, Line=LineNo)
909    if len(TokenList) < 2:
910        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACROVALUE_NOGIVEN,
911                        ExtraData=LineContent, File=FileName, Line=LineNo)
912
913    Name, Value = TokenList
914
915    #
916    # DEFINE defined macros
917    #
918    if SectionType == DataType.MODEL_META_DATA_HEADER:
919        FileLocalMacros[Name] = Value
920
921    ReIsValidMacroName = re.compile(r"^[A-Z][A-Z0-9_]*$", re.DOTALL)
922    if ReIsValidMacroName.match(Name) == None:
923        Logger.Error('Parser',
924                     FORMAT_INVALID,
925                     ST.ERR_MACRONAME_INVALID % (Name),
926                     ExtraData=LineContent,
927                     File=FileName,
928                     Line=LineNo)
929
930    # Validate MACRO Value
931    #
932    # <MacroDefinition> ::=  [<Comments>]{0,}
933    #                       "DEFINE" <MACRO> "=" [{<PATH>} {<VALUE>}] <EOL>
934    # <Value>           ::=  {<NumVal>} {<Boolean>} {<AsciiString>} {<GUID>}
935    #                        {<CString>} {<UnicodeString>} {<CArray>}
936    #
937    # The definition of <NumVal>, <PATH>, <Boolean>, <GUID>, <CString>,
938    # <UnicodeString>, <CArray> are subset of <AsciiString>.
939    #
940    ReIsValidMacroValue = re.compile(r"^[\x20-\x7e]*$", re.DOTALL)
941    if ReIsValidMacroValue.match(Value) == None:
942        Logger.Error('Parser',
943                     FORMAT_INVALID,
944                     ST.ERR_MACROVALUE_INVALID % (Value),
945                     ExtraData=LineContent,
946                     File=FileName,
947                     Line=LineNo)
948
949    return Name, Value
950
951## GenSection
952#
953# generate section contents
954#
955# @param  SectionName:  indicate the name of the section, details refer to
956#                       INF, DEC specs
957# @param  SectionDict:  section statement dict, key is SectionAttrs(arch,
958#                       moduletype or platform may exist as needed) list
959#                       seperated by space,
960#                       value is statement
961#
962def GenSection(SectionName, SectionDict, SplitArch=True, NeedBlankLine=False):
963    Content = ''
964    for SectionAttrs in SectionDict:
965        StatementList = SectionDict[SectionAttrs]
966        if SectionAttrs and SectionName != 'Defines' and SectionAttrs.strip().upper() != DataType.TAB_ARCH_COMMON:
967            if SplitArch:
968                ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_SPACE_SPLIT)
969            else:
970                if SectionName != 'UserExtensions':
971                    ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_COMMENT_SPLIT)
972                else:
973                    ArchList = [SectionAttrs]
974            for Index in xrange(0, len(ArchList)):
975                ArchList[Index] = ConvertArchForInstall(ArchList[Index])
976            Section = '[' + SectionName + '.' + (', ' + SectionName + '.').join(ArchList) + ']'
977        else:
978            Section = '[' + SectionName + ']'
979        Content += '\n' + Section + '\n'
980        if StatementList != None:
981            for Statement in StatementList:
982                LineList = Statement.split('\n')
983                NewStatement = ""
984                for Line in LineList:
985                    # ignore blank comment
986                    if not Line.replace("#", '').strip() and SectionName not in ('Defines', 'Hob', 'Event', 'BootMode'):
987                        continue
988                    # add two space before non-comments line except the comments in Defines section
989                    if Line.strip().startswith('#') and SectionName == 'Defines':
990                        NewStatement += "%s\n" % Line
991                        continue
992                    NewStatement += "  %s\n" % Line
993                if NeedBlankLine:
994                    Content += NewStatement + '\n'
995                else:
996                    Content += NewStatement
997
998        if NeedBlankLine:
999            Content = Content[:-1]
1000    if not Content.replace('\\n', '').strip():
1001        return ''
1002    return Content
1003
1004## ConvertArchForInstall
1005# if Arch.upper() is in "IA32", "X64", "IPF", and "EBC", it must be upper case.  "common" must be lower case.
1006# Anything else, the case must be preserved
1007#
1008# @param Arch: the arch string that need to be converted, it should be stripped before pass in
1009# @return: the arch string that get converted
1010#
1011def ConvertArchForInstall(Arch):
1012    if Arch.upper() in [DataType.TAB_ARCH_IA32, DataType.TAB_ARCH_X64,
1013                                   DataType.TAB_ARCH_IPF, DataType.TAB_ARCH_EBC]:
1014        Arch = Arch.upper()
1015    elif Arch.upper() == DataType.TAB_ARCH_COMMON:
1016        Arch = Arch.lower()
1017
1018    return Arch
1019