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    PackageDir = GlobalData.gPACKAGE_PATH
831    for PkgRoot in [WorkspaceDir] + PackageDir:
832        for Root, Dirs, Files in os.walk(PkgRoot):
833            if 'CVS' in Dirs:
834                Dirs.remove('CVS')
835            if '.svn' in Dirs:
836                Dirs.remove('.svn')
837            for Dir in Dirs:
838                if Dir.startswith('.'):
839                    Dirs.remove(Dir)
840            for FileSp in Files:
841                if FileSp.startswith('.'):
842                    continue
843                Ext = os.path.splitext(FileSp)[1]
844                if Ext.lower() in ['.dec']:
845                    DecFileList.append\
846                    (os.path.normpath(os.path.join(Root, FileSp)))
847    #
848    # abstract package guid, version info from DecFile List
849    #
850    PkgList = []
851    for DecFile in DecFileList:
852        (PkgName, PkgGuid, PkgVersion) = GetPkgInfoFromDec(DecFile)
853        if PkgName and PkgGuid and PkgVersion:
854            PkgList.append((PkgName, PkgGuid, PkgVersion, DecFile))
855
856    return PkgList
857
858## GetWorkspaceModule
859#
860# Get a list of workspace modules.
861#
862def GetWorkspaceModule():
863    InfFileList = []
864    WorkspaceDir = GlobalData.gWORKSPACE
865    for Root, Dirs, Files in os.walk(WorkspaceDir):
866        if 'CVS' in Dirs:
867            Dirs.remove('CVS')
868        if '.svn' in Dirs:
869            Dirs.remove('.svn')
870        if 'Build' in Dirs:
871            Dirs.remove('Build')
872        for Dir in Dirs:
873            if Dir.startswith('.'):
874                Dirs.remove(Dir)
875        for FileSp in Files:
876            if FileSp.startswith('.'):
877                continue
878            Ext = os.path.splitext(FileSp)[1]
879            if Ext.lower() in ['.inf']:
880                InfFileList.append\
881                (os.path.normpath(os.path.join(Root, FileSp)))
882
883    return InfFileList
884
885## MacroParser used to parse macro definition
886#
887# @param Line:            The content contain linestring and line number
888# @param FileName:        The meta-file file name
889# @param SectionType:     Section for the Line belong to
890# @param FileLocalMacros: A list contain Macro defined in [Defines] section.
891#
892def MacroParser(Line, FileName, SectionType, FileLocalMacros):
893    MacroDefPattern = re.compile("^(DEFINE)[ \t]+")
894    LineContent = Line[0]
895    LineNo = Line[1]
896    Match = MacroDefPattern.match(LineContent)
897    if not Match:
898        #
899        # Not 'DEFINE/EDK_GLOBAL' statement, call decorated method
900        #
901        return None, None
902
903    TokenList = GetSplitValueList(LineContent[Match.end(1):], \
904                                  DataType.TAB_EQUAL_SPLIT, 1)
905    #
906    # Syntax check
907    #
908    if not TokenList[0]:
909        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACRONAME_NOGIVEN,
910                        ExtraData=LineContent, File=FileName, Line=LineNo)
911    if len(TokenList) < 2:
912        Logger.Error('Parser', FORMAT_INVALID, ST.ERR_MACROVALUE_NOGIVEN,
913                        ExtraData=LineContent, File=FileName, Line=LineNo)
914
915    Name, Value = TokenList
916
917    #
918    # DEFINE defined macros
919    #
920    if SectionType == DataType.MODEL_META_DATA_HEADER:
921        FileLocalMacros[Name] = Value
922
923    ReIsValidMacroName = re.compile(r"^[A-Z][A-Z0-9_]*$", re.DOTALL)
924    if ReIsValidMacroName.match(Name) == None:
925        Logger.Error('Parser',
926                     FORMAT_INVALID,
927                     ST.ERR_MACRONAME_INVALID % (Name),
928                     ExtraData=LineContent,
929                     File=FileName,
930                     Line=LineNo)
931
932    # Validate MACRO Value
933    #
934    # <MacroDefinition> ::=  [<Comments>]{0,}
935    #                       "DEFINE" <MACRO> "=" [{<PATH>} {<VALUE>}] <EOL>
936    # <Value>           ::=  {<NumVal>} {<Boolean>} {<AsciiString>} {<GUID>}
937    #                        {<CString>} {<UnicodeString>} {<CArray>}
938    #
939    # The definition of <NumVal>, <PATH>, <Boolean>, <GUID>, <CString>,
940    # <UnicodeString>, <CArray> are subset of <AsciiString>.
941    #
942    ReIsValidMacroValue = re.compile(r"^[\x20-\x7e]*$", re.DOTALL)
943    if ReIsValidMacroValue.match(Value) == None:
944        Logger.Error('Parser',
945                     FORMAT_INVALID,
946                     ST.ERR_MACROVALUE_INVALID % (Value),
947                     ExtraData=LineContent,
948                     File=FileName,
949                     Line=LineNo)
950
951    return Name, Value
952
953## GenSection
954#
955# generate section contents
956#
957# @param  SectionName:  indicate the name of the section, details refer to
958#                       INF, DEC specs
959# @param  SectionDict:  section statement dict, key is SectionAttrs(arch,
960#                       moduletype or platform may exist as needed) list
961#                       seperated by space,
962#                       value is statement
963#
964def GenSection(SectionName, SectionDict, SplitArch=True, NeedBlankLine=False):
965    Content = ''
966    for SectionAttrs in SectionDict:
967        StatementList = SectionDict[SectionAttrs]
968        if SectionAttrs and SectionName != 'Defines' and SectionAttrs.strip().upper() != DataType.TAB_ARCH_COMMON:
969            if SplitArch:
970                ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_SPACE_SPLIT)
971            else:
972                if SectionName != 'UserExtensions':
973                    ArchList = GetSplitValueList(SectionAttrs, DataType.TAB_COMMENT_SPLIT)
974                else:
975                    ArchList = [SectionAttrs]
976            for Index in xrange(0, len(ArchList)):
977                ArchList[Index] = ConvertArchForInstall(ArchList[Index])
978            Section = '[' + SectionName + '.' + (', ' + SectionName + '.').join(ArchList) + ']'
979        else:
980            Section = '[' + SectionName + ']'
981        Content += '\n' + Section + '\n'
982        if StatementList != None:
983            for Statement in StatementList:
984                LineList = Statement.split('\n')
985                NewStatement = ""
986                for Line in LineList:
987                    # ignore blank comment
988                    if not Line.replace("#", '').strip() and SectionName not in ('Defines', 'Hob', 'Event', 'BootMode'):
989                        continue
990                    # add two space before non-comments line except the comments in Defines section
991                    if Line.strip().startswith('#') and SectionName == 'Defines':
992                        NewStatement += "%s\n" % Line
993                        continue
994                    NewStatement += "  %s\n" % Line
995                if NeedBlankLine:
996                    Content += NewStatement + '\n'
997                else:
998                    Content += NewStatement
999
1000        if NeedBlankLine:
1001            Content = Content[:-1]
1002    if not Content.replace('\\n', '').strip():
1003        return ''
1004    return Content
1005
1006## ConvertArchForInstall
1007# if Arch.upper() is in "IA32", "X64", "IPF", and "EBC", it must be upper case.  "common" must be lower case.
1008# Anything else, the case must be preserved
1009#
1010# @param Arch: the arch string that need to be converted, it should be stripped before pass in
1011# @return: the arch string that get converted
1012#
1013def ConvertArchForInstall(Arch):
1014    if Arch.upper() in [DataType.TAB_ARCH_IA32, DataType.TAB_ARCH_X64,
1015                                   DataType.TAB_ARCH_IPF, DataType.TAB_ARCH_EBC]:
1016        Arch = Arch.upper()
1017    elif Arch.upper() == DataType.TAB_ARCH_COMMON:
1018        Arch = Arch.lower()
1019
1020    return Arch
1021