You've already forked slimbootloader
mirror of
https://github.com/Dasharo/slimbootloader.git
synced 2026-03-06 15:26:20 -08:00
Convert the line endings stored for all text files in the repository to LF. The majority previously used DOS-style CRLF line endings. Add a .gitattributes file to enforce this and treat certain extensions as never being text files. Update PatchCheck.py to insist on LF line endings rather than CRLF. However, its other checks fail on this commit due to lots of pre-existing complaints that it only notices because the line endings have changed. Silicon/QemuSocPkg/FspBin/Patches/0001-Build-QEMU-FSP-2.0-binaries.patch needs to be treated as binary since it contains a mixture of line endings. This change has implications depending on the client platform you are using the repository from: * Windows The usual configuration for Git on Windows means that text files will be checked out to the work tree with DOS-style CRLF line endings. If that's not the case then you can configure Git to do so for the entire machine with: git config --global core.autocrlf true or for just the repository with: git config core.autocrlf true Line endings will be normalised to LF when they are committed to the repository. If you commit a text file with only LF line endings then it will be converted to CRLF line endings in your work tree. * Linux, MacOS and other Unices The usual configuration for Git on such platforms is to check files out of the repository with LF line endings. This is probably the right thing for you. In the unlikely even that you are using Git on Unix but editing or compiling on Windows for some reason then you may need to tweak your configuration to force the use of CRLF line endings as described above. * General For more information see https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings . Fixes: https://github.com/slimbootloader/slimbootloader/issues/1400 Signed-off-by: Mike Crowe <mac@mcrowe.com>
907 lines
37 KiB
Python
907 lines
37 KiB
Python
## @file
|
|
# This file is used to define common parsing related functions used in parsing INF/DEC/DSC process
|
|
#
|
|
# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
#
|
|
|
|
##
|
|
# Import Modules
|
|
#
|
|
from __future__ import absolute_import
|
|
from .StringUtils import *
|
|
from CommonDataClass.DataClass import *
|
|
from .DataType import *
|
|
|
|
## 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]
|
|
|
|
#
|
|
# Overridden by Global Macros
|
|
#
|
|
Macros.update(GlobalMacro)
|
|
|
|
#
|
|
# Replace the Macros
|
|
#
|
|
for Value in (v for v in RecordSets.values() if v):
|
|
for Item in Value:
|
|
Item[0] = ReplaceMacro(Item[0], Macros)
|
|
|
|
## 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') *
|
|
# where ID in (select ID from %s *
|
|
# where Model = %s *
|
|
# and Value1 like '%%%s%%' *
|
|
# and StartLine > %s *
|
|
# and Enabled > -1 *
|
|
# and Arch = '%s')""" % \ *
|
|
# (self.TblDsc.Table, Record[0], Record[1], self.TblDsc.Table, Record[2], Record[1], Record[3], Record[4]) *
|
|
#***************************************************************************************************************************************************
|
|
Macros[Record[0]] = Record[1]
|
|
|
|
#
|
|
# Overridden by Global Macros
|
|
#
|
|
Macros.update(GlobalMacro)
|
|
|
|
#
|
|
# 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)
|
|
|
|
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):
|
|
(Family, ToolChain, Flag) = ('', '', '')
|
|
if String.find(TAB_EQUAL_SPLIT) < 0:
|
|
RaiseParserError(String, 'BuildOptions', File, '[<Family>:]<ToolFlag>=Flag', LineNo)
|
|
else:
|
|
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()
|
|
return (Family, ToolChain, Flag)
|
|
|
|
## Get Library Class
|
|
#
|
|
# Get Library of Dsc as <LibraryClassKeyWord>|<LibraryInstance>
|
|
#
|
|
# @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>]
|
|
#
|
|
# @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]
|
|
|
|
return (ItemList[0], ItemList[1], ItemList[2], SupMod)
|
|
|
|
## 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>'
|
|
if TokenInfoString != '' and TokenInfoString is not None:
|
|
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>]
|
|
#
|
|
# @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)
|
|
|
|
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]
|
|
|
|
if CheckPcdTokenInfo(List[0], 'Pcds' + Type, ContainerFile, LineNo):
|
|
(TokenGuid, TokenName) = GetSplitValueList(List[0], TAB_SPLIT)
|
|
|
|
return (TokenName, TokenGuid, Value, MaximumDatumSize, Token, Type)
|
|
|
|
## Get FeatureFlagPcd
|
|
#
|
|
# Get FeatureFlagPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|TRUE/FALSE
|
|
#
|
|
# @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)
|
|
|
|
return (TokenName, TokenGuid, Value, Type)
|
|
|
|
## Get DynamicDefaultPcd
|
|
#
|
|
# Get DynamicDefaultPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<Value>[|<DatumTyp>[|<MaxDatumSize>]]
|
|
#
|
|
# @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)
|
|
|
|
return (TokenName, TokenGuid, Value, DatumTyp, MaxDatumSize, Type)
|
|
|
|
## Get DynamicHiiPcd
|
|
#
|
|
# Get DynamicHiiPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<String>|<VariableGuidCName>|<VariableOffset>[|<DefaultValue>[|<MaximumDatumSize>]]
|
|
#
|
|
# @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)
|
|
|
|
return (TokenName, TokenGuid, L1, L2, L3, L4, L5, Type)
|
|
|
|
## Get DynamicVpdPcd
|
|
#
|
|
# Get DynamicVpdPcd of Dsc as <PcdTokenSpaceGuidCName>.<TokenCName>|<VpdOffset>[|<MaximumDatumSize>]
|
|
#
|
|
# @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)
|
|
|
|
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]
|
|
|
|
#
|
|
# Ignore !include statement
|
|
#
|
|
if Line.upper().find(TAB_INCLUDE.upper() + ' ') > -1 or Line.upper().find(TAB_DEFINE + ' ') > -1:
|
|
continue
|
|
|
|
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
|
|
# @param Key: Reserved
|
|
# @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)
|
|
if Line is None or Line == '':
|
|
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>]]]]
|
|
#
|
|
# @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>]]]]
|
|
#
|
|
# @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])
|
|
# @retval List
|
|
#
|
|
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)
|
|
|
|
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], '', '', '')
|
|
|
|
## Get Guids/Protocols/Ppis
|
|
#
|
|
# Get Guids/Protocols/Ppis of Inf as <GuidCName>[|<PcdFeatureFlag>]
|
|
#
|
|
# @param Item: String as <GuidCName>[|<PcdFeatureFlag>]
|
|
# @param Type: Type of parsing string
|
|
# @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)
|
|
|
|
return (List[0], List[1])
|
|
|
|
## Get Guids/Protocols/Ppis
|
|
#
|
|
# Get Guids/Protocols/Ppis of Dec as <GuidCName>=<GuidValue>
|
|
#
|
|
# @param Item: String as <GuidCName>=<GuidValue>
|
|
# @param Type: Type of parsing string
|
|
# @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)
|
|
|
|
return (List[0], List[1])
|
|
|
|
## GetPackage
|
|
#
|
|
# Get Package of Inf as <PackagePath>[|<PcdFeatureFlag>]
|
|
#
|
|
# @param Item: String as <PackagePath>[|<PcdFeatureFlag>]
|
|
# @param Type: Type of parsing string
|
|
# @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)
|
|
|
|
if List[1] != '':
|
|
CheckPcdTokenInfo(List[1], 'Packages', ContainerFile, LineNo)
|
|
|
|
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 = '', '', '', ''
|
|
|
|
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:
|
|
InfType = TAB_INF_FEATURE_PCD
|
|
elif Type == TAB_PCDS_DYNAMIC_EX:
|
|
InfType = TAB_INF_PCD_EX
|
|
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)
|
|
|
|
|
|
## 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]
|
|
|
|
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
|
|
#
|
|
# 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]
|
|
|
|
EdkLogger.debug(4, "Parsing %s ..." %LineValue)
|
|
# And then parse DEFINE statement
|
|
if LineValue.upper().find(DataType.TAB_DEFINE.upper() + ' ') > -1:
|
|
continue
|
|
|
|
# At last parse other sections
|
|
ID = -1
|
|
Records.append([LineValue, Arch, StartLine, ID, Third, Comment])
|
|
|
|
if RecordSet != {}:
|
|
RecordSet[Model] = Records
|
|
|
|
## Insert records to database
|
|
#
|
|
# Insert item data of a section to database
|
|
# @param Table: The Table to be inserted
|
|
# @param FileID: The ID of belonging file
|
|
# @param Filename: The name of belonging file
|
|
# @param CurrentSection: The name of current section
|
|
# @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
|
|
# @param RecordSet: A dict of all parsed records
|
|
#
|
|
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]
|
|
|
|
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
|
|
|
|
#
|
|
# 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])
|
|
|
|
if RecordSet != {}:
|
|
RecordSet[Model] = Records
|
|
|
|
## GenMetaDatSectionItem
|
|
def GenMetaDatSectionItem(Key, Value, List):
|
|
if Key not in List:
|
|
List[Key] = [Value]
|
|
else:
|
|
List[Key].append(Value)
|
|
|
|
## 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
|