2009-07-17 11:10:31 +02:00
## @file
2010-03-01 00:39:39 +01:00
# This file is used to define common parsing related functions used in parsing INF/DEC/DSC process
2009-07-17 11:10:31 +02:00
#
2018-04-17 16:40:15 +02:00
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
2019-04-04 01:03:11 +02:00
# SPDX-License-Identifier: BSD-2-Clause-Patent
2009-07-17 11:10:31 +02:00
#
##
# Import Modules
#
2018-10-15 02:27:53 +02:00
from __future__ import absolute_import
2018-07-13 12:18:40 +02:00
from . StringUtils import *
2009-07-17 11:10:31 +02:00
from CommonDataClass . DataClass import *
2018-07-13 12:18:40 +02:00
from . DataType import *
2009-07-17 11:10:31 +02:00
## ParseDefineMacro
#
# Search whole table to find all defined Macro and replaced them with the real values
#
def ParseDefineMacro2 ( Table , RecordSets , GlobalMacro ) :
Macros = { }
#
# Find all DEFINE macros in section [Header] and its section
#
SqlCommand = """ select Value1, Value2, BelongsToItem, StartLine, Arch from %s
where Model = % s
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_DEFINE)
RecordSet = Table . Exec ( SqlCommand )
for Record in RecordSet :
Macros [ Record [ 0 ] ] = Record [ 1 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
#
2019-02-06 08:44:39 +01:00
# Overridden by Global Macros
2009-07-17 11:10:31 +02:00
#
2018-04-17 16:40:15 +02:00
Macros . update ( GlobalMacro )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
#
# Replace the Macros
#
2018-04-17 16:40:15 +02:00
for Value in ( v for v in RecordSets . values ( ) if v ) :
for Item in Value :
Item [ 0 ] = ReplaceMacro ( Item [ 0 ] , Macros )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
## ParseDefineMacro
#
# Search whole table to find all defined Macro and replaced them with the real values
#
def ParseDefineMacro ( Table , GlobalMacro ) :
Macros = { }
#
# Find all DEFINE macros
#
SqlCommand = """ select Value1, Value2, BelongsToItem, StartLine, Arch from %s
where Model = % s
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_DEFINE)
RecordSet = Table . Exec ( SqlCommand )
for Record in RecordSet :
#***************************************************************************************************************************************************
# The follow SqlCommand (expr replace) is not supported in Sqlite 3.3.4 which is used in Python 2.5 *
# Reserved Only *
# SqlCommand = """update %s set Value1 = replace(Value1, '%s', '%s') *
2010-03-01 00:39:39 +01:00
# where ID in (select ID from %s *
2009-07-17 11:10:31 +02:00
# where Model = %s *
# and Value1 like '%%%s%%' *
# and StartLine > %s *
# and Enabled > -1 *
2010-03-01 00:39:39 +01:00
# and Arch = '%s')""" % \ *
2009-07-17 11:10:31 +02:00
# (self.TblDsc.Table, Record[0], Record[1], self.TblDsc.Table, Record[2], Record[1], Record[3], Record[4]) *
#***************************************************************************************************************************************************
Macros [ Record [ 0 ] ] = Record [ 1 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
#
2019-02-06 08:44:39 +01:00
# Overridden by Global Macros
2009-07-17 11:10:31 +02:00
#
2018-04-17 16:40:15 +02:00
Macros . update ( GlobalMacro )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
#
# Found all defined macro and replaced
#
SqlCommand = """ select ID, Value1 from %s
where Model != % s
and Value1 like ' %% $( %% ' and Value1 like ' %% ) %% '
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_DEFINE)
FoundRecords = Table . Exec ( SqlCommand )
for FoundRecord in FoundRecords :
NewValue = ReplaceMacro ( FoundRecord [ 1 ] , Macros )
SqlCommand = """ update %s set Value1 = ' %s '
where ID = % s """ % (Table.Table, ConvertToSqlString2(NewValue), FoundRecord[0])
Table . Exec ( SqlCommand )
##QueryDefinesItem
#
# Search item of section [Defines] by name, return its values
#
# @param Table: The Table to be executed
# @param Name: The Name of item of section [Defines]
# @param Arch: The Arch of item of section [Defines]
#
# @retval RecordSet: A list of all matched records
#
def QueryDefinesItem ( Table , Name , Arch , BelongsToFile ) :
SqlCommand = """ select Value2 from %s
where Model = % s
and Value1 = ' %s '
and Arch = ' %s '
and BelongsToFile = % s
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(Arch), BelongsToFile)
RecordSet = Table . Exec ( SqlCommand )
if len ( RecordSet ) < 1 :
SqlCommand = """ select Value2 from %s
where Model = % s
and Value1 = ' %s '
and Arch = ' %s '
and BelongsToFile = % s
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Name), ConvertToSqlString2(TAB_ARCH_COMMON.upper()), BelongsToFile)
RecordSet = Table . Exec ( SqlCommand )
if len ( RecordSet ) == 1 :
if Name == TAB_INF_DEFINES_LIBRARY_CLASS :
return [ RecordSet [ 0 ] [ 0 ] ]
else :
return GetSplitValueList ( RecordSet [ 0 ] [ 0 ] )
elif len ( RecordSet ) < 1 :
return [ ' ' ]
elif len ( RecordSet ) > 1 :
RetVal = [ ]
for Record in RecordSet :
if Name == TAB_INF_DEFINES_LIBRARY_CLASS :
RetVal . append ( Record [ 0 ] )
else :
Items = GetSplitValueList ( Record [ 0 ] )
for Item in Items :
RetVal . append ( Item )
return RetVal
##QueryDefinesItem
#
# Search item of section [Defines] by name, return its values
#
# @param Table: The Table to be executed
# @param Name: The Name of item of section [Defines]
# @param Arch: The Arch of item of section [Defines]
#
# @retval RecordSet: A list of all matched records
#
def QueryDefinesItem2 ( Table , Arch , BelongsToFile ) :
SqlCommand = """ select Value1, Value2, StartLine from %s
where Model = % s
and Arch = ' %s '
and BelongsToFile = % s
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(Arch), BelongsToFile)
RecordSet = Table . Exec ( SqlCommand )
if len ( RecordSet ) < 1 :
SqlCommand = """ select Value1, Value2, StartLine from %s
where Model = % s
and Arch = ' %s '
and BelongsToFile = % s
and Enabled > - 1 """ % (Table.Table, MODEL_META_DATA_HEADER, ConvertToSqlString2(TAB_ARCH_COMMON), BelongsToFile)
RecordSet = Table . Exec ( SqlCommand )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return RecordSet
##QueryDscItem
#
# Search all dsc item for a specific section
#
# @param Table: The Table to be executed
# @param Model: The type of section
#
# @retval RecordSet: A list of all matched records
#
def QueryDscItem ( Table , Model , BelongsToItem , BelongsToFile ) :
SqlCommand = """ select Value1, Arch, StartLine, ID, Value2 from %s
where Model = % s
and BelongsToItem = % s
and BelongsToFile = % s
and Enabled > - 1 """ % (Table.Table, Model, BelongsToItem, BelongsToFile)
return Table . Exec ( SqlCommand )
##QueryDecItem
#
# Search all dec item for a specific section
#
# @param Table: The Table to be executed
# @param Model: The type of section
#
# @retval RecordSet: A list of all matched records
#
def QueryDecItem ( Table , Model , BelongsToItem ) :
SqlCommand = """ select Value1, Arch, StartLine, ID, Value2 from %s
where Model = % s
and BelongsToItem = % s
and Enabled > - 1 """ % (Table.Table, Model, BelongsToItem)
return Table . Exec ( SqlCommand )
##QueryInfItem
#
# Search all dec item for a specific section
#
# @param Table: The Table to be executed
# @param Model: The type of section
#
# @retval RecordSet: A list of all matched records
#
def QueryInfItem ( Table , Model , BelongsToItem ) :
SqlCommand = """ select Value1, Arch, StartLine, ID, Value2 from %s
where Model = % s
and BelongsToItem = % s
and Enabled > - 1 """ % (Table.Table, Model, BelongsToItem)
return Table . Exec ( SqlCommand )
## GetBuildOption
#
# Parse a string with format "[<Family>:]<ToolFlag>=Flag"
# Return (Family, ToolFlag, Flag)
#
# @param String: String with BuildOption statement
# @param File: The file which defines build option, used in error report
#
# @retval truple() A truple structure as (Family, ToolChain, Flag)
#
def GetBuildOption ( String , File , LineNo = - 1 ) :
2010-03-12 11:54:01 +01:00
( Family , ToolChain , Flag ) = ( ' ' , ' ' , ' ' )
2009-07-17 11:10:31 +02:00
if String . find ( TAB_EQUAL_SPLIT ) < 0 :
RaiseParserError ( String , ' BuildOptions ' , File , ' [<Family>:]<ToolFlag>=Flag ' , LineNo )
else :
2010-03-12 11:54:01 +01:00
List = GetSplitValueList ( String , TAB_EQUAL_SPLIT , MaxSplit = 1 )
if List [ 0 ] . find ( ' : ' ) > - 1 :
Family = List [ 0 ] [ : List [ 0 ] . find ( ' : ' ) ] . strip ( )
ToolChain = List [ 0 ] [ List [ 0 ] . find ( ' : ' ) + 1 : ] . strip ( )
else :
ToolChain = List [ 0 ] . strip ( )
Flag = List [ 1 ] . strip ( )
2009-07-17 11:10:31 +02:00
return ( Family , ToolChain , Flag )
## Get Library Class
#
# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance>
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item
#
def GetLibraryClass ( Item , ContainerFile , WorkspaceDir , LineNo = - 1 ) :
List = GetSplitValueList ( Item [ 0 ] )
SupMod = SUP_MODULE_LIST_STRING
if len ( List ) != 2 :
RaiseParserError ( Item [ 0 ] , ' LibraryClasses ' , ContainerFile , ' <LibraryClassKeyWord>|<LibraryInstance> ' )
else :
CheckFileType ( List [ 1 ] , ' .Inf ' , ContainerFile , ' library class instance ' , Item [ 0 ] , LineNo )
CheckFileExist ( WorkspaceDir , List [ 1 ] , ContainerFile , ' LibraryClasses ' , Item [ 0 ] , LineNo )
if Item [ 1 ] != ' ' :
SupMod = Item [ 1 ]
return ( List [ 0 ] , List [ 1 ] , SupMod )
## Get Library Class
#
# Get Library of Dsc as <LibraryClassKeyWord>[|<LibraryInstance>][|<TokenSpaceGuidCName>.<PcdCName>]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <LibraryClassKeyWord>|<LibraryInstance>
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (LibraryClassKeyWord, LibraryInstance, [SUP_MODULE_LIST]) Formatted Library Item
#
def GetLibraryClassOfInf ( Item , ContainerFile , WorkspaceDir , LineNo = - 1 ) :
ItemList = GetSplitValueList ( ( Item [ 0 ] + DataType . TAB_VALUE_SPLIT * 2 ) )
SupMod = SUP_MODULE_LIST_STRING
if len ( ItemList ) > 5 :
RaiseParserError ( Item [ 0 ] , ' LibraryClasses ' , ContainerFile , ' <LibraryClassKeyWord>[|<LibraryInstance>][|<TokenSpaceGuidCName>.<PcdCName>] ' )
else :
CheckFileType ( ItemList [ 1 ] , ' .Inf ' , ContainerFile , ' LibraryClasses ' , Item [ 0 ] , LineNo )
CheckFileExist ( WorkspaceDir , ItemList [ 1 ] , ContainerFile , ' LibraryClasses ' , Item [ 0 ] , LineNo )
if ItemList [ 2 ] != ' ' :
CheckPcdTokenInfo ( ItemList [ 2 ] , ' LibraryClasses ' , ContainerFile , LineNo )
if Item [ 1 ] != ' ' :
SupMod = Item [ 1 ]
2010-03-01 00:39:39 +01:00
return ( ItemList [ 0 ] , ItemList [ 1 ] , ItemList [ 2 ] , SupMod )
2009-07-17 11:10:31 +02:00
## CheckPcdTokenInfo
#
# Check if PcdTokenInfo is following <TokenSpaceGuidCName>.<PcdCName>
#
# @param TokenInfoString: String to be checked
# @param Section: Used for error report
# @param File: Used for error report
#
# @retval True PcdTokenInfo is in correct format
#
def CheckPcdTokenInfo ( TokenInfoString , Section , File , LineNo = - 1 ) :
Format = ' <TokenSpaceGuidCName>.<PcdCName> '
2018-03-26 22:25:43 +02:00
if TokenInfoString != ' ' and TokenInfoString is not None :
2009-07-17 11:10:31 +02:00
TokenInfoList = GetSplitValueList ( TokenInfoString , TAB_SPLIT )
if len ( TokenInfoList ) == 2 :
return True
RaiseParserError ( TokenInfoString , Section , File , Format , LineNo )
## Get Pcd
#
# Get Pcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>]
# @param ContainerFile: The file which describes the pcd, used for error report
#
# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type)
#
def GetPcd ( Item , Type , ContainerFile , LineNo = - 1 ) :
TokenGuid , TokenName , Value , MaximumDatumSize , Token = ' ' , ' ' , ' ' , ' ' , ' '
List = GetSplitValueList ( Item + TAB_VALUE_SPLIT * 2 )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if len ( List ) < 4 or len ( List ) > 6 :
RaiseParserError ( Item , ' Pcds ' + Type , ContainerFile , ' <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<Type>|<MaximumDatumSize>] ' , LineNo )
else :
Value = List [ 1 ]
MaximumDatumSize = List [ 2 ]
Token = List [ 3 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if CheckPcdTokenInfo ( List [ 0 ] , ' Pcds ' + Type , ContainerFile , LineNo ) :
( TokenGuid , TokenName ) = GetSplitValueList ( List [ 0 ] , TAB_SPLIT )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( TokenName , TokenGuid , Value , MaximumDatumSize , Token , Type )
## Get FeatureFlagPcd
#
# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
# @param ContainerFile: The file which describes the pcd, used for error report
#
# @retval (TokenInfo[1], TokenInfo[0], List[1], Type)
#
def GetFeatureFlagPcd ( Item , Type , ContainerFile , LineNo = - 1 ) :
TokenGuid , TokenName , Value = ' ' , ' ' , ' '
List = GetSplitValueList ( Item )
if len ( List ) != 2 :
RaiseParserError ( Item , ' Pcds ' + Type , ContainerFile , ' <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE ' , LineNo )
else :
Value = List [ 1 ]
if CheckPcdTokenInfo ( List [ 0 ] , ' Pcds ' + Type , ContainerFile , LineNo ) :
( TokenGuid , TokenName ) = GetSplitValueList ( List [ 0 ] , DataType . TAB_SPLIT )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( TokenName , TokenGuid , Value , Type )
## Get DynamicDefaultPcd
#
# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
# @param ContainerFile: The file which describes the pcd, used for error report
#
# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], Type)
#
def GetDynamicDefaultPcd ( Item , Type , ContainerFile , LineNo = - 1 ) :
TokenGuid , TokenName , Value , DatumTyp , MaxDatumSize = ' ' , ' ' , ' ' , ' ' , ' '
List = GetSplitValueList ( Item + TAB_VALUE_SPLIT * 2 )
if len ( List ) < 4 or len ( List ) > 8 :
RaiseParserError ( Item , ' Pcds ' + Type , ContainerFile , ' <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]] ' , LineNo )
else :
Value = List [ 1 ]
DatumTyp = List [ 2 ]
MaxDatumSize = List [ 3 ]
if CheckPcdTokenInfo ( List [ 0 ] , ' Pcds ' + Type , ContainerFile , LineNo ) :
( TokenGuid , TokenName ) = GetSplitValueList ( List [ 0 ] , TAB_SPLIT )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( TokenName , TokenGuid , Value , DatumTyp , MaxDatumSize , Type )
## Get DynamicHiiPcd
#
# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
# @param ContainerFile: The file which describes the pcd, used for error report
#
# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], List[3], List[4], List[5], Type)
#
def GetDynamicHiiPcd ( Item , Type , ContainerFile , LineNo = - 1 ) :
TokenGuid , TokenName , L1 , L2 , L3 , L4 , L5 = ' ' , ' ' , ' ' , ' ' , ' ' , ' ' , ' '
List = GetSplitValueList ( Item + TAB_VALUE_SPLIT * 2 )
if len ( List ) < 6 or len ( List ) > 8 :
RaiseParserError ( Item , ' Pcds ' + Type , ContainerFile , ' <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]] ' , LineNo )
else :
L1 , L2 , L3 , L4 , L5 = List [ 1 ] , List [ 2 ] , List [ 3 ] , List [ 4 ] , List [ 5 ]
if CheckPcdTokenInfo ( List [ 0 ] , ' Pcds ' + Type , ContainerFile , LineNo ) :
( TokenGuid , TokenName ) = GetSplitValueList ( List [ 0 ] , DataType . TAB_SPLIT )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( TokenName , TokenGuid , L1 , L2 , L3 , L4 , L5 , Type )
## Get DynamicVpdPcd
#
# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
# @param ContainerFile: The file which describes the pcd, used for error report
#
# @retval (TokenInfo[1], TokenInfo[0], List[1], List[2], Type)
#
def GetDynamicVpdPcd ( Item , Type , ContainerFile , LineNo = - 1 ) :
TokenGuid , TokenName , L1 , L2 = ' ' , ' ' , ' ' , ' '
List = GetSplitValueList ( Item + TAB_VALUE_SPLIT )
if len ( List ) < 3 or len ( List ) > 4 :
RaiseParserError ( Item , ' Pcds ' + Type , ContainerFile , ' <PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>] ' , LineNo )
else :
L1 , L2 = List [ 1 ] , List [ 2 ]
if CheckPcdTokenInfo ( List [ 0 ] , ' Pcds ' + Type , ContainerFile , LineNo ) :
( TokenGuid , TokenName ) = GetSplitValueList ( List [ 0 ] , DataType . TAB_SPLIT )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( TokenName , TokenGuid , L1 , L2 , Type )
## GetComponent
#
# Parse block of the components defined in dsc file
# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
#
# @param Lines: The content to be parsed
# @param KeyValues: To store data after parsing
#
# @retval True Get component successfully
#
def GetComponent ( Lines , KeyValues ) :
( findBlock , findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , False , False , False )
ListItem = None
LibraryClassItem = [ ]
BuildOption = [ ]
Pcd = [ ]
for Line in Lines :
Line = Line [ 0 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
#
# Ignore !include statement
#
if Line . upper ( ) . find ( TAB_INCLUDE . upper ( ) + ' ' ) > - 1 or Line . upper ( ) . find ( TAB_DEFINE + ' ' ) > - 1 :
continue
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if findBlock == False :
ListItem = Line
#
# find '{' at line tail
#
if Line . endswith ( ' { ' ) :
findBlock = True
ListItem = CleanString ( Line . rsplit ( ' { ' , 1 ) [ 0 ] , DataType . TAB_COMMENT_SPLIT )
#
# Parse a block content
#
if findBlock :
if Line . find ( ' <LibraryClasses> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( True , False , False , False , False , False , False )
continue
if Line . find ( ' <BuildOptions> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , True , False , False , False , False , False )
continue
if Line . find ( ' <PcdsFeatureFlag> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , True , False , False , False , False )
continue
if Line . find ( ' <PcdsPatchableInModule> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , True , False , False , False )
continue
if Line . find ( ' <PcdsFixedAtBuild> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , True , False , False )
continue
if Line . find ( ' <PcdsDynamic> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , True , False )
continue
if Line . find ( ' <PcdsDynamicEx> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , False , True )
continue
if Line . endswith ( ' } ' ) :
#
# find '}' at line tail
#
KeyValues . append ( [ ListItem , LibraryClassItem , BuildOption , Pcd ] )
( findBlock , findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , False , False , False )
LibraryClassItem , BuildOption , Pcd = [ ] , [ ] , [ ]
continue
if findBlock :
if findLibraryClass :
LibraryClassItem . append ( Line )
elif findBuildOption :
BuildOption . append ( Line )
elif findPcdsFeatureFlag :
Pcd . append ( ( DataType . TAB_PCDS_FEATURE_FLAG_NULL , Line ) )
elif findPcdsPatchableInModule :
Pcd . append ( ( DataType . TAB_PCDS_PATCHABLE_IN_MODULE_NULL , Line ) )
elif findPcdsFixedAtBuild :
Pcd . append ( ( DataType . TAB_PCDS_FIXED_AT_BUILD_NULL , Line ) )
elif findPcdsDynamic :
Pcd . append ( ( DataType . TAB_PCDS_DYNAMIC_DEFAULT_NULL , Line ) )
elif findPcdsDynamicEx :
Pcd . append ( ( DataType . TAB_PCDS_DYNAMIC_EX_DEFAULT_NULL , Line ) )
else :
KeyValues . append ( [ ListItem , [ ] , [ ] , [ ] ] )
return True
## GetExec
#
# Parse a string with format "InfFilename [EXEC = ExecFilename]"
# Return (InfFilename, ExecFilename)
#
# @param String: String with EXEC statement
#
# @retval truple() A pair as (InfFilename, ExecFilename)
#
def GetExec ( String ) :
InfFilename = ' '
ExecFilename = ' '
if String . find ( ' EXEC ' ) > - 1 :
InfFilename = String [ : String . find ( ' EXEC ' ) ] . strip ( )
ExecFilename = String [ String . find ( ' EXEC ' ) + len ( ' EXEC ' ) : ] . strip ( )
else :
InfFilename = String . strip ( )
return ( InfFilename , ExecFilename )
## GetComponents
#
# Parse block of the components defined in dsc file
# Set KeyValues as [ ['component name', [lib1, lib2, lib3], [bo1, bo2, bo3], [pcd1, pcd2, pcd3]], ...]
#
# @param Lines: The content to be parsed
2010-03-01 00:39:39 +01:00
# @param Key: Reserved
2009-07-17 11:10:31 +02:00
# @param KeyValues: To store data after parsing
# @param CommentCharacter: Comment char, used to ignore comment content
#
# @retval True Get component successfully
#
def GetComponents ( Lines , Key , KeyValues , CommentCharacter ) :
if Lines . find ( DataType . TAB_SECTION_END ) > - 1 :
Lines = Lines . split ( DataType . TAB_SECTION_END , 1 ) [ 1 ]
( findBlock , findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , False , False , False )
ListItem = None
LibraryClassItem = [ ]
BuildOption = [ ]
Pcd = [ ]
LineList = Lines . split ( ' \n ' )
for Line in LineList :
Line = CleanString ( Line , CommentCharacter )
2018-03-26 22:25:43 +02:00
if Line is None or Line == ' ' :
2009-07-17 11:10:31 +02:00
continue
if findBlock == False :
ListItem = Line
#
# find '{' at line tail
#
if Line . endswith ( ' { ' ) :
findBlock = True
ListItem = CleanString ( Line . rsplit ( ' { ' , 1 ) [ 0 ] , CommentCharacter )
#
# Parse a block content
#
if findBlock :
if Line . find ( ' <LibraryClasses> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( True , False , False , False , False , False , False )
continue
if Line . find ( ' <BuildOptions> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , True , False , False , False , False , False )
continue
if Line . find ( ' <PcdsFeatureFlag> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , True , False , False , False , False )
continue
if Line . find ( ' <PcdsPatchableInModule> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , True , False , False , False )
continue
if Line . find ( ' <PcdsFixedAtBuild> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , True , False , False )
continue
if Line . find ( ' <PcdsDynamic> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , True , False )
continue
if Line . find ( ' <PcdsDynamicEx> ' ) != - 1 :
( findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , False , True )
continue
if Line . endswith ( ' } ' ) :
#
# find '}' at line tail
#
KeyValues . append ( [ ListItem , LibraryClassItem , BuildOption , Pcd ] )
( findBlock , findLibraryClass , findBuildOption , findPcdsFeatureFlag , findPcdsPatchableInModule , findPcdsFixedAtBuild , findPcdsDynamic , findPcdsDynamicEx ) = ( False , False , False , False , False , False , False , False )
LibraryClassItem , BuildOption , Pcd = [ ] , [ ] , [ ]
continue
if findBlock :
if findLibraryClass :
LibraryClassItem . append ( Line )
elif findBuildOption :
BuildOption . append ( Line )
elif findPcdsFeatureFlag :
Pcd . append ( ( DataType . TAB_PCDS_FEATURE_FLAG , Line ) )
elif findPcdsPatchableInModule :
Pcd . append ( ( DataType . TAB_PCDS_PATCHABLE_IN_MODULE , Line ) )
elif findPcdsFixedAtBuild :
Pcd . append ( ( DataType . TAB_PCDS_FIXED_AT_BUILD , Line ) )
elif findPcdsDynamic :
Pcd . append ( ( DataType . TAB_PCDS_DYNAMIC , Line ) )
elif findPcdsDynamicEx :
Pcd . append ( ( DataType . TAB_PCDS_DYNAMIC_EX , Line ) )
else :
KeyValues . append ( [ ListItem , [ ] , [ ] , [ ] ] )
return True
## Get Source
#
# Get Source of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (List[0], List[1], List[2], List[3], List[4])
#
def GetSource ( Item , ContainerFile , FileRelativePath , LineNo = - 1 ) :
ItemNew = Item + DataType . TAB_VALUE_SPLIT * 4
List = GetSplitValueList ( ItemNew )
if len ( List ) < 5 or len ( List ) > 9 :
RaiseParserError ( Item , ' Sources ' , ContainerFile , ' <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]] ' , LineNo )
List [ 0 ] = NormPath ( List [ 0 ] )
CheckFileExist ( FileRelativePath , List [ 0 ] , ContainerFile , ' Sources ' , Item , LineNo )
if List [ 4 ] != ' ' :
CheckPcdTokenInfo ( List [ 4 ] , ' Sources ' , ContainerFile , LineNo )
return ( List [ 0 ] , List [ 1 ] , List [ 2 ] , List [ 3 ] , List [ 4 ] )
## Get Binary
#
# Get Binary of Inf as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# @param Item: String as <Filename>[|<Family>[|<TagName>[|<ToolCode>[|<PcdFeatureFlag>]]]]
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (List[0], List[1], List[2], List[3])
2010-03-01 00:39:39 +01:00
# @retval List
2009-07-17 11:10:31 +02:00
#
def GetBinary ( Item , ContainerFile , FileRelativePath , LineNo = - 1 ) :
ItemNew = Item + DataType . TAB_VALUE_SPLIT
List = GetSplitValueList ( ItemNew )
if len ( List ) != 4 and len ( List ) != 5 :
RaiseParserError ( Item , ' Binaries ' , ContainerFile , " <FileType>|<Filename>|<Target>[|<TokenSpaceGuidCName>.<PcdCName>] " , LineNo )
else :
if List [ 3 ] != ' ' :
CheckPcdTokenInfo ( List [ 3 ] , ' Binaries ' , ContainerFile , LineNo )
2010-03-01 00:39:39 +01:00
if len ( List ) == 4 :
return ( List [ 0 ] , List [ 1 ] , List [ 2 ] , List [ 3 ] )
elif len ( List ) == 3 :
return ( List [ 0 ] , List [ 1 ] , List [ 2 ] , ' ' )
elif len ( List ) == 2 :
return ( List [ 0 ] , List [ 1 ] , ' ' , ' ' )
elif len ( List ) == 1 :
return ( List [ 0 ] , ' ' , ' ' , ' ' )
2009-07-17 11:10:31 +02:00
## Get Guids/Protocols/Ppis
#
# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
#
# @param Item: String as <GuidCName>[|<PcdFeatureFlag>]
2010-03-01 00:39:39 +01:00
# @param Type: Type of parsing string
2009-07-17 11:10:31 +02:00
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (List[0], List[1])
#
def GetGuidsProtocolsPpisOfInf ( Item , Type , ContainerFile , LineNo = - 1 ) :
ItemNew = Item + TAB_VALUE_SPLIT
List = GetSplitValueList ( ItemNew )
if List [ 1 ] != ' ' :
CheckPcdTokenInfo ( List [ 1 ] , Type , ContainerFile , LineNo )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( List [ 0 ] , List [ 1 ] )
## Get Guids/Protocols/Ppis
#
# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
#
# @param Item: String as <GuidCName>=<GuidValue>
2010-03-01 00:39:39 +01:00
# @param Type: Type of parsing string
2009-07-17 11:10:31 +02:00
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (List[0], List[1])
#
def GetGuidsProtocolsPpisOfDec ( Item , Type , ContainerFile , LineNo = - 1 ) :
List = GetSplitValueList ( Item , DataType . TAB_EQUAL_SPLIT )
if len ( List ) != 2 :
RaiseParserError ( Item , Type , ContainerFile , ' <CName>=<GuidValue> ' , LineNo )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( List [ 0 ] , List [ 1 ] )
## GetPackage
#
# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
#
# @param Item: String as <PackagePath>[|<PcdFeatureFlag>]
2010-03-01 00:39:39 +01:00
# @param Type: Type of parsing string
2009-07-17 11:10:31 +02:00
# @param ContainerFile: The file which describes the library class, used for error report
#
# @retval (List[0], List[1])
#
def GetPackage ( Item , ContainerFile , FileRelativePath , LineNo = - 1 ) :
ItemNew = Item + TAB_VALUE_SPLIT
List = GetSplitValueList ( ItemNew )
CheckFileType ( List [ 0 ] , ' .Dec ' , ContainerFile , ' package ' , List [ 0 ] , LineNo )
CheckFileExist ( FileRelativePath , List [ 0 ] , ContainerFile , ' Packages ' , List [ 0 ] , LineNo )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if List [ 1 ] != ' ' :
CheckPcdTokenInfo ( List [ 1 ] , ' Packages ' , ContainerFile , LineNo )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( List [ 0 ] , List [ 1 ] )
## Get Pcd Values of Inf
#
# Get Pcd of Inf as <TokenSpaceGuidCName>.<PcdCName>[|<Value>]
#
# @param Item: The string describes pcd
# @param Type: The type of Pcd
# @param File: The file which describes the pcd, used for error report
#
# @retval (TokenSpcCName, TokenCName, Value, ItemType) Formatted Pcd Item
#
def GetPcdOfInf ( Item , Type , File , LineNo ) :
Format = ' <TokenSpaceGuidCName>.<PcdCName>[|<Value>] '
TokenGuid , TokenName , Value , InfType = ' ' , ' ' , ' ' , ' '
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if Type == TAB_PCDS_FIXED_AT_BUILD :
InfType = TAB_INF_FIXED_PCD
elif Type == TAB_PCDS_PATCHABLE_IN_MODULE :
InfType = TAB_INF_PATCH_PCD
elif Type == TAB_PCDS_FEATURE_FLAG :
2010-03-01 00:39:39 +01:00
InfType = TAB_INF_FEATURE_PCD
2009-07-17 11:10:31 +02:00
elif Type == TAB_PCDS_DYNAMIC_EX :
2010-03-01 00:39:39 +01:00
InfType = TAB_INF_PCD_EX
2009-07-17 11:10:31 +02:00
elif Type == TAB_PCDS_DYNAMIC :
InfType = TAB_INF_PCD
List = GetSplitValueList ( Item + DataType . TAB_VALUE_SPLIT )
if len ( List ) < 2 or len ( List ) > 3 :
RaiseParserError ( Item , InfType , File , Format , LineNo )
else :
Value = List [ 1 ]
TokenInfo = GetSplitValueList ( List [ 0 ] , DataType . TAB_SPLIT )
if len ( TokenInfo ) != 2 :
RaiseParserError ( Item , InfType , File , Format , LineNo )
else :
TokenGuid = TokenInfo [ 0 ]
TokenName = TokenInfo [ 1 ]
return ( TokenGuid , TokenName , Value , Type )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
## Get Pcd Values of Dec
#
# Get Pcd of Dec as <TokenSpcCName>.<TokenCName>|<Value>|<DatumType>|<Token>
# @retval (TokenSpcCName, TokenCName, Value, DatumType, Token, ItemType) Formatted Pcd Item
#
def GetPcdOfDec ( Item , Type , File , LineNo = - 1 ) :
Format = ' <TokenSpaceGuidCName>.<PcdCName>|<Value>|<DatumType>|<Token> '
TokenGuid , TokenName , Value , DatumType , Token = ' ' , ' ' , ' ' , ' ' , ' '
List = GetSplitValueList ( Item )
if len ( List ) != 4 :
RaiseParserError ( Item , ' Pcds ' + Type , File , Format , LineNo )
else :
Value = List [ 1 ]
DatumType = List [ 2 ]
Token = List [ 3 ]
TokenInfo = GetSplitValueList ( List [ 0 ] , DataType . TAB_SPLIT )
if len ( TokenInfo ) != 2 :
RaiseParserError ( Item , ' Pcds ' + Type , File , Format , LineNo )
else :
TokenGuid = TokenInfo [ 0 ]
TokenName = TokenInfo [ 1 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
return ( TokenGuid , TokenName , Value , DatumType , Token , Type )
## Parse DEFINE statement
#
# Get DEFINE macros
#
# 1. Insert a record into TblDec
# Value1: Macro Name
# Value2: Macro Value
#
def ParseDefine ( LineValue , StartLine , Table , FileID , Filename , SectionName , SectionModel , Arch ) :
EdkLogger . debug ( EdkLogger . DEBUG_2 , " DEFINE statement ' %s ' found in section %s " % ( LineValue , SectionName ) )
Define = GetSplitValueList ( CleanString ( LineValue [ LineValue . upper ( ) . find ( DataType . TAB_DEFINE . upper ( ) + ' ' ) + len ( DataType . TAB_DEFINE + ' ' ) : ] ) , TAB_EQUAL_SPLIT , 1 )
Table . Insert ( MODEL_META_DATA_DEFINE , Define [ 0 ] , Define [ 1 ] , ' ' , ' ' , ' ' , Arch , SectionModel , FileID , StartLine , - 1 , StartLine , - 1 , 0 )
## InsertSectionItems
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# Insert item data of a section to a dict
#
def InsertSectionItems ( Model , CurrentSection , SectionItemList , ArchList , ThirdList , RecordSet ) :
# Insert each item data of a section
for Index in range ( 0 , len ( ArchList ) ) :
Arch = ArchList [ Index ]
Third = ThirdList [ Index ]
if Arch == ' ' :
Arch = TAB_ARCH_COMMON
Records = RecordSet [ Model ]
for SectionItem in SectionItemList :
BelongsToItem , EndLine , EndColumn = - 1 , - 1 , - 1
LineValue , StartLine , EndLine , Comment = SectionItem [ 0 ] , SectionItem [ 1 ] , SectionItem [ 1 ] , SectionItem [ 2 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
EdkLogger . debug ( 4 , " Parsing %s ... " % LineValue )
# And then parse DEFINE statement
if LineValue . upper ( ) . find ( DataType . TAB_DEFINE . upper ( ) + ' ' ) > - 1 :
continue
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
# At last parse other sections
ID = - 1
Records . append ( [ LineValue , Arch , StartLine , ID , Third , Comment ] )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if RecordSet != { } :
RecordSet [ Model ] = Records
## Insert records to database
2010-03-01 00:39:39 +01:00
#
2009-07-17 11:10:31 +02:00
# Insert item data of a section to database
2010-03-01 00:39:39 +01:00
# @param Table: The Table to be inserted
2009-07-17 11:10:31 +02:00
# @param FileID: The ID of belonging file
# @param Filename: The name of belonging file
2019-02-06 08:44:39 +01:00
# @param CurrentSection: The name of current section
2009-07-17 11:10:31 +02:00
# @param SectionItemList: A list of items of the section
# @param ArchList: A list of arches
# @param ThirdList: A list of third parameters, ModuleType for LibraryClass and SkuId for Dynamic Pcds
# @param IfDefList: A list of all conditional statements
2010-03-01 00:39:39 +01:00
# @param RecordSet: A dict of all parsed records
2009-07-17 11:10:31 +02:00
#
def InsertSectionItemsIntoDatabase ( Table , FileID , Filename , Model , CurrentSection , SectionItemList , ArchList , ThirdList , IfDefList , RecordSet ) :
#
# Insert each item data of a section
#
for Index in range ( 0 , len ( ArchList ) ) :
Arch = ArchList [ Index ]
Third = ThirdList [ Index ]
if Arch == ' ' :
Arch = TAB_ARCH_COMMON
Records = RecordSet [ Model ]
for SectionItem in SectionItemList :
BelongsToItem , EndLine , EndColumn = - 1 , - 1 , - 1
LineValue , StartLine , EndLine = SectionItem [ 0 ] , SectionItem [ 1 ] , SectionItem [ 1 ]
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
EdkLogger . debug ( 4 , " Parsing %s ... " % LineValue )
#
# And then parse DEFINE statement
#
if LineValue . upper ( ) . find ( DataType . TAB_DEFINE . upper ( ) + ' ' ) > - 1 :
ParseDefine ( LineValue , StartLine , Table , FileID , Filename , CurrentSection , Model , Arch )
continue
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
#
# At last parse other sections
#
ID = Table . Insert ( Model , LineValue , Third , Third , ' ' , ' ' , Arch , - 1 , FileID , StartLine , - 1 , StartLine , - 1 , 0 )
Records . append ( [ LineValue , Arch , StartLine , ID , Third ] )
2010-03-01 00:39:39 +01:00
2009-07-17 11:10:31 +02:00
if RecordSet != { } :
RecordSet [ Model ] = Records
## GenMetaDatSectionItem
def GenMetaDatSectionItem ( Key , Value , List ) :
if Key not in List :
List [ Key ] = [ Value ]
else :
2010-11-15 03:51:34 +01:00
List [ Key ] . append ( Value )
2014-07-01 09:10:10 +02:00
## IsValidWord
#
# Check whether the word is valid.
# <Word> ::= (a-zA-Z0-9_)(a-zA-Z0-9_-){0,} Alphanumeric characters with
# optional
# dash "-" and/or underscore "_" characters. No whitespace
# characters are permitted.
#
# @param Word: The word string need to be checked.
#
def IsValidWord ( Word ) :
if not Word :
return False
#
# The first char should be alpha, _ or Digit.
#
if not Word [ 0 ] . isalnum ( ) and \
not Word [ 0 ] == ' _ ' and \
not Word [ 0 ] . isdigit ( ) :
return False
LastChar = ' '
for Char in Word [ 1 : ] :
if ( not Char . isalpha ( ) ) and \
( not Char . isdigit ( ) ) and \
Char != ' - ' and \
Char != ' _ ' and \
Char != ' . ' :
return False
if Char == ' . ' and LastChar == ' . ' :
return False
LastChar = Char
return True