Home | History | Annotate | Download | only in Common
      1 ## @file

      2 # This file is used to define common string related functions used in parsing process

      3 #

      4 # Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>

      5 # This program and the accompanying materials

      6 # are licensed and made available under the terms and conditions of the BSD License

      7 # which accompanies this distribution.  The full text of the license may be found at

      8 # http://opensource.org/licenses/bsd-license.php

      9 #

     10 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

     11 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

     12 #

     13 
     14 ##

     15 # Import Modules

     16 #

     17 import re
     18 import DataType
     19 import Common.LongFilePathOs as os
     20 import string
     21 import EdkLogger as EdkLogger
     22 
     23 import GlobalData
     24 from BuildToolError import *
     25 from CommonDataClass.Exceptions import *
     26 from Common.LongFilePathSupport import OpenLongFilePath as open
     27 from Common.MultipleWorkspace import MultipleWorkspace as mws
     28 
     29 gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE)
     30 gHumanReadableVerPatt = re.compile(r'([1-9][0-9]*|0)\.[0-9]{1,2}$')
     31 
     32 ## GetSplitValueList

     33 #

     34 # Get a value list from a string with multiple values splited with SplitTag

     35 # The default SplitTag is DataType.TAB_VALUE_SPLIT

     36 # 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']

     37 #

     38 # @param String:    The input string to be splitted

     39 # @param SplitTag:  The split key, default is DataType.TAB_VALUE_SPLIT

     40 # @param MaxSplit:  The max number of split values, default is -1

     41 #

     42 # @retval list() A list for splitted string

     43 #

     44 def GetSplitValueList(String, SplitTag=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):
     45     ValueList = []
     46     Last = 0
     47     Escaped = False
     48     InString = False
     49     for Index in range(0, len(String)):
     50         Char = String[Index]
     51 
     52         if not Escaped:
     53             # Found a splitter not in a string, split it

     54             if not InString and Char == SplitTag:
     55                 ValueList.append(String[Last:Index].strip())
     56                 Last = Index + 1
     57                 if MaxSplit > 0 and len(ValueList) >= MaxSplit:
     58                     break
     59 
     60             if Char == '\\' and InString:
     61                 Escaped = True
     62             elif Char == '"':
     63                 if not InString:
     64                     InString = True
     65                 else:
     66                     InString = False
     67         else:
     68             Escaped = False
     69 
     70     if Last < len(String):
     71         ValueList.append(String[Last:].strip())
     72     elif Last == len(String):
     73         ValueList.append('')
     74 
     75     return ValueList
     76 
     77 ## GetSplitList
     78 #
     79 # Get a value list from a string with multiple values splited with SplitString
     80 # The default SplitTag is DataType.TAB_VALUE_SPLIT
     81 # 'AAA|BBB|CCC' -> ['AAA', 'BBB', 'CCC']
     82 #
     83 # @param String:    The input string to be splitted
     84 # @param SplitStr:  The split key, default is DataType.TAB_VALUE_SPLIT
     85 # @param MaxSplit:  The max number of split values, default is -1
     86 #
     87 # @retval list() A list for splitted string
     88 #
     89 def GetSplitList(String, SplitStr=DataType.TAB_VALUE_SPLIT, MaxSplit= -1):
     90     return map(lambda l: l.strip(), String.split(SplitStr, MaxSplit))
     91 
     92 ## MergeArches
     93 #
     94 # Find a key's all arches in dict, add the new arch to the list
     95 # If not exist any arch, set the arch directly
     96 #
     97 # @param Dict:  The input value for Dict
     98 # @param Key:   The input value for Key
     99 # @param Arch:  The Arch to be added or merged
    100 #
    101 def MergeArches(Dict, Key, Arch):
    102     if Key in Dict.keys():
    103         Dict[Key].append(Arch)
    104     else:
    105         Dict[Key] = Arch.split()
    106 
    107 ## GenDefines
    108 #
    109 # Parse a string with format "DEFINE <VarName> = <PATH>"
    110 # Generate a map Defines[VarName] = PATH
    111 # Return False if invalid format
    112 #
    113 # @param String:   String with DEFINE statement
    114 # @param Arch:     Supportted Arch
    115 # @param Defines:  DEFINE statement to be parsed
    116 #
    117 # @retval 0   DEFINE statement found, and valid
    118 # @retval 1   DEFINE statement found, but not valid
    119 # @retval -1  DEFINE statement not found
    120 #
    121 def GenDefines(String, Arch, Defines):
    122     if String.find(DataType.TAB_DEFINE + ' ') > -1:
    123         List = String.replace(DataType.TAB_DEFINE + ' ', '').split(DataType.TAB_EQUAL_SPLIT)
    124         if len(List) == 2:
    125             Defines[(CleanString(List[0]), Arch)] = CleanString(List[1])
    126             return 0
    127         else:
    128             return -1
    129 
    130     return 1
    131 
    132 ## GenInclude
    133 #
    134 # Parse a string with format "!include <Filename>"
    135 # Return the file path
    136 # Return False if invalid format or NOT FOUND
    137 #
    138 # @param String:        String with INCLUDE statement
    139 # @param IncludeFiles:  INCLUDE statement to be parsed
    140 # @param Arch:          Supportted Arch
    141 #
    142 # @retval True
    143 # @retval False
    144 #
    145 def GenInclude(String, IncludeFiles, Arch):
    146     if String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') > -1:
    147         IncludeFile = CleanString(String[String.upper().find(DataType.TAB_INCLUDE.upper() + ' ') + len(DataType.TAB_INCLUDE + ' ') : ])
    148         MergeArches(IncludeFiles, IncludeFile, Arch)
    149         return True
    150     else:
    151         return False
    152 
    153 ## GetLibraryClassesWithModuleType
    154 #
    155 # Get Library Class definition when no module type defined
    156 #
    157 # @param Lines:             The content to be parsed
    158 # @param Key:               Reserved
    159 # @param KeyValues:         To store data after parsing
    160 # @param CommentCharacter:  Comment char, used to ignore comment content
    161 #
    162 # @retval True Get library classes successfully
    163 #
    164 def GetLibraryClassesWithModuleType(Lines, Key, KeyValues, CommentCharacter):
    165     newKey = SplitModuleType(Key)
    166     Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
    167     LineList = Lines.splitlines()
    168     for Line in LineList:
    169         Line = CleanString(Line, CommentCharacter)
    170         if Line != '' and Line[0] != CommentCharacter:
    171             KeyValues.append([CleanString(Line, CommentCharacter), newKey[1]])
    172 
    173     return True
    174 
    175 ## GetDynamics
    176 #
    177 # Get Dynamic Pcds
    178 #
    179 # @param Lines:             The content to be parsed
    180 # @param Key:               Reserved
    181 # @param KeyValues:         To store data after parsing
    182 # @param CommentCharacter:  Comment char, used to ignore comment content
    183 #
    184 # @retval True Get Dynamic Pcds successfully
    185 #
    186 def GetDynamics(Lines, Key, KeyValues, CommentCharacter):
    187     #
    188     # Get SkuId Name List
    189     #
    190     SkuIdNameList = SplitModuleType(Key)
    191 
    192     Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
    193     LineList = Lines.splitlines()
    194     for Line in LineList:
    195         Line = CleanString(Line, CommentCharacter)
    196         if Line != '' and Line[0] != CommentCharacter:
    197             KeyValues.append([CleanString(Line, CommentCharacter), SkuIdNameList[1]])
    198 
    199     return True
    200 
    201 ## SplitModuleType
    202 #
    203 # Split ModuleType out of section defien to get key
    204 # [LibraryClass.Arch.ModuleType|ModuleType|ModuleType] -> [ 'LibraryClass.Arch', ['ModuleType', 'ModuleType', 'ModuleType'] ]
    205 #
    206 # @param Key:  String to be parsed
    207 #
    208 # @retval ReturnValue A list for module types
    209 #
    210 def SplitModuleType(Key):
    211     KeyList = Key.split(DataType.TAB_SPLIT)
    212     #
    213     # Fill in for arch
    214     #
    215     KeyList.append('')
    216     #
    217     # Fill in for moduletype
    218     #
    219     KeyList.append('')
    220     ReturnValue = []
    221     KeyValue = KeyList[0]
    222     if KeyList[1] != '':
    223         KeyValue = KeyValue + DataType.TAB_SPLIT + KeyList[1]
    224     ReturnValue.append(KeyValue)
    225     ReturnValue.append(GetSplitValueList(KeyList[2]))
    226 
    227     return ReturnValue
    228 
    229 ## Replace macro in strings list
    230 #
    231 # This method replace macros used in a given string list. The macros are
    232 # given in a dictionary.
    233 #
    234 # @param StringList         StringList to be processed
    235 # @param MacroDefinitions   The macro definitions in the form of dictionary
    236 # @param SelfReplacement    To decide whether replace un-defined macro to ''
    237 #
    238 # @retval NewList           A new string list whose macros are replaced
    239 #
    240 def ReplaceMacros(StringList, MacroDefinitions={}, SelfReplacement=False):
    241     NewList = []
    242     for String in StringList:
    243         if type(String) == type(''):
    244             NewList.append(ReplaceMacro(String, MacroDefinitions, SelfReplacement))
    245         else:
    246             NewList.append(String)
    247 
    248     return NewList
    249 
    250 ## Replace macro in string
    251 #
    252 # This method replace macros used in given string. The macros are given in a
    253 # dictionary.
    254 #
    255 # @param String             String to be processed
    256 # @param MacroDefinitions   The macro definitions in the form of dictionary
    257 # @param SelfReplacement    To decide whether replace un-defined macro to ''
    258 #
    259 # @retval string            The string whose macros are replaced
    260 #
    261 def ReplaceMacro(String, MacroDefinitions={}, SelfReplacement=False, RaiseError=False):
    262     LastString = String
    263     while String and MacroDefinitions:
    264         MacroUsed = GlobalData.gMacroRefPattern.findall(String)
    265         # no macro found in String, stop replacing
    266         if len(MacroUsed) == 0:
    267             break
    268 
    269         for Macro in MacroUsed:
    270             if Macro not in MacroDefinitions:
    271                 if RaiseError:
    272                     raise SymbolNotFound("%s not defined" % Macro)
    273                 if SelfReplacement:
    274                     String = String.replace("$(%s)" % Macro, '')
    275                 continue
    276             if "$(%s)" % Macro not in MacroDefinitions[Macro]:
    277                 String = String.replace("$(%s)" % Macro, MacroDefinitions[Macro])
    278         # in case there's macro not defined
    279         if String == LastString:
    280             break
    281         LastString = String
    282 
    283     return String
    284 
    285 ## NormPath
    286 #
    287 # Create a normal path
    288 # And replace DFEINE in the path
    289 #
    290 # @param Path:     The input value for Path to be converted
    291 # @param Defines:  A set for DEFINE statement
    292 #
    293 # @retval Path Formatted path
    294 #
    295 def NormPath(Path, Defines={}):
    296     IsRelativePath = False
    297     if Path:
    298         if Path[0] == '.':
    299             IsRelativePath = True
    300         #
    301         # Replace with Define
    302         #
    303         if Defines:
    304             Path = ReplaceMacro(Path, Defines)
    305         #
    306         # To local path format
    307         #
    308         Path = os.path.normpath(Path)
    309         if Path.startswith(GlobalData.gWorkspace) and not os.path.exists(Path):
    310             Path = Path[len (GlobalData.gWorkspace):]
    311             if Path[0] == os.path.sep:
    312                 Path = Path[1:]
    313             Path = mws.join(GlobalData.gWorkspace, Path)
    314 
    315     if IsRelativePath and Path[0] != '.':
    316         Path = os.path.join('.', Path)
    317 
    318     return Path
    319 
    320 ## CleanString
    321 #
    322 # Remove comments in a string
    323 # Remove spaces
    324 #
    325 # @param Line:              The string to be cleaned
    326 # @param CommentCharacter:  Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT
    327 #
    328 # @retval Path Formatted path
    329 #
    330 def CleanString(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False, BuildOption=False):
    331     #
    332     # remove whitespace
    333     #
    334     Line = Line.strip();
    335     #
    336     # Replace Edk's comment character
    337     #
    338     if AllowCppStyleComment:
    339         Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)
    340     #
    341     # remove comments, but we should escape comment character in string
    342     #
    343     InString = False
    344     CommentInString = False
    345     for Index in range(0, len(Line)):
    346         if Line[Index] == '"':
    347             InString = not InString
    348         elif Line[Index] == CommentCharacter and InString :
    349             CommentInString = True
    350         elif Line[Index] == CommentCharacter and not InString :
    351             Line = Line[0: Index]
    352             break
    353 
    354     if CommentInString and BuildOption:
    355         Line = Line.replace('"', '')
    356         ChIndex = Line.find('#')
    357         while ChIndex >= 0:
    358             if GlobalData.gIsWindows:
    359                 if ChIndex == 0 or Line[ChIndex - 1] != '^':
    360                     Line = Line[0:ChIndex] + '^' + Line[ChIndex:]
    361                     ChIndex = Line.find('#', ChIndex + 2)
    362                 else:
    363                     ChIndex = Line.find('#', ChIndex + 1)
    364             else:
    365                 if ChIndex == 0 or Line[ChIndex - 1] != '\\':
    366                     Line = Line[0:ChIndex] + '\\' + Line[ChIndex:]
    367                     ChIndex = Line.find('#', ChIndex + 2)
    368                 else:
    369                     ChIndex = Line.find('#', ChIndex + 1)
    370     #
    371     # remove whitespace again
    372     #
    373     Line = Line.strip();
    374 
    375     return Line
    376 
    377 ## CleanString2
    378 #
    379 # Split statement with comments in a string
    380 # Remove spaces
    381 #
    382 # @param Line:              The string to be cleaned
    383 # @param CommentCharacter:  Comment char, used to ignore comment content, default is DataType.TAB_COMMENT_SPLIT
    384 #
    385 # @retval Path Formatted path
    386 #
    387 def CleanString2(Line, CommentCharacter=DataType.TAB_COMMENT_SPLIT, AllowCppStyleComment=False):
    388     #
    389     # remove whitespace
    390     #
    391     Line = Line.strip();
    392     #
    393     # Replace Edk's comment character
    394     #
    395     if AllowCppStyleComment:
    396         Line = Line.replace(DataType.TAB_COMMENT_EDK_SPLIT, CommentCharacter)
    397     #
    398     # separate comments and statements, but we should escape comment character in string
    399     #
    400     InString = False
    401     CommentInString = False
    402     Comment = ''
    403     for Index in range(0, len(Line)):
    404         if Line[Index] == '"':
    405             InString = not InString
    406         elif Line[Index] == CommentCharacter and InString:
    407             CommentInString = True
    408         elif Line[Index] == CommentCharacter and not InString:
    409             Comment = Line[Index:].strip()
    410             Line = Line[0:Index].strip()
    411             break
    412 
    413     return Line, Comment
    414 
    415 ## GetMultipleValuesOfKeyFromLines
    416 #
    417 # Parse multiple strings to clean comment and spaces
    418 # The result is saved to KeyValues
    419 #
    420 # @param Lines:             The content to be parsed
    421 # @param Key:               Reserved
    422 # @param KeyValues:         To store data after parsing
    423 # @param CommentCharacter:  Comment char, used to ignore comment content
    424 #
    425 # @retval True Successfully executed
    426 #
    427 def GetMultipleValuesOfKeyFromLines(Lines, Key, KeyValues, CommentCharacter):
    428     Lines = Lines.split(DataType.TAB_SECTION_END, 1)[1]
    429     LineList = Lines.split('\n')
    430     for Line in LineList:
    431         Line = CleanString(Line, CommentCharacter)
    432         if Line != '' and Line[0] != CommentCharacter:
    433             KeyValues += [Line]
    434 
    435     return True
    436 
    437 ## GetDefineValue
    438 #
    439 # Parse a DEFINE statement to get defined value
    440 # DEFINE Key Value
    441 #
    442 # @param String:            The content to be parsed
    443 # @param Key:               The key of DEFINE statement
    444 # @param CommentCharacter:  Comment char, used to ignore comment content
    445 #
    446 # @retval string The defined value
    447 #
    448 def GetDefineValue(String, Key, CommentCharacter):
    449     String = CleanString(String)
    450     return String[String.find(Key + ' ') + len(Key + ' ') : ]
    451 
    452 ## GetHexVerValue
    453 #
    454 # Get a Hex Version Value
    455 #
    456 # @param VerString:         The version string to be parsed
    457 #
    458 #
    459 # @retval:      If VerString is incorrectly formatted, return "None" which will break the build.
    460 #               If VerString is correctly formatted, return a Hex value of the Version Number (0xmmmmnnnn)
    461 #                   where mmmm is the major number and nnnn is the adjusted minor number.
    462 #
    463 def GetHexVerValue(VerString):
    464     VerString = CleanString(VerString)
    465 
    466     if gHumanReadableVerPatt.match(VerString):
    467         ValueList = VerString.split('.')
    468         Major = ValueList[0]
    469         Minor = ValueList[1]
    470         if len(Minor) == 1:
    471             Minor += '0'
    472         DeciValue = (int(Major) << 16) + int(Minor);
    473         return "0x%08x" % DeciValue
    474     elif gHexVerPatt.match(VerString):
    475         return VerString
    476     else:
    477         return None
    478 
    479 
    480 ## GetSingleValueOfKeyFromLines
    481 #
    482 # Parse multiple strings as below to get value of each definition line
    483 # Key1 = Value1
    484 # Key2 = Value2
    485 # The result is saved to Dictionary
    486 #
    487 # @param Lines:                The content to be parsed
    488 # @param Dictionary:           To store data after parsing
    489 # @param CommentCharacter:     Comment char, be used to ignore comment content
    490 # @param KeySplitCharacter:    Key split char, between key name and key value. Key1 = Value1, '=' is the key split char
    491 # @param ValueSplitFlag:       Value split flag, be used to decide if has multiple values
    492 # @param ValueSplitCharacter:  Value split char, be used to split multiple values. Key1 = Value1|Value2, '|' is the value split char
    493 #
    494 # @retval True Successfully executed
    495 #
    496 def GetSingleValueOfKeyFromLines(Lines, Dictionary, CommentCharacter, KeySplitCharacter, ValueSplitFlag, ValueSplitCharacter):
    497     Lines = Lines.split('\n')
    498     Keys = []
    499     Value = ''
    500     DefineValues = ['']
    501     SpecValues = ['']
    502 
    503     for Line in Lines:
    504         #
    505         # Handle DEFINE and SPEC
    506         #
    507         if Line.find(DataType.TAB_INF_DEFINES_DEFINE + ' ') > -1:
    508             if '' in DefineValues:
    509                 DefineValues.remove('')
    510             DefineValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_DEFINE, CommentCharacter))
    511             continue
    512         if Line.find(DataType.TAB_INF_DEFINES_SPEC + ' ') > -1:
    513             if '' in SpecValues:
    514                 SpecValues.remove('')
    515             SpecValues.append(GetDefineValue(Line, DataType.TAB_INF_DEFINES_SPEC, CommentCharacter))
    516             continue
    517 
    518         #
    519         # Handle Others
    520         #
    521         LineList = Line.split(KeySplitCharacter, 1)
    522         if len(LineList) >= 2:
    523             Key = LineList[0].split()
    524             if len(Key) == 1 and Key[0][0] != CommentCharacter:
    525                 #
    526                 # Remove comments and white spaces
    527                 #
    528                 LineList[1] = CleanString(LineList[1], CommentCharacter)
    529                 if ValueSplitFlag:
    530                     Value = map(string.strip, LineList[1].split(ValueSplitCharacter))
    531                 else:
    532                     Value = CleanString(LineList[1], CommentCharacter).splitlines()
    533 
    534                 if Key[0] in Dictionary:
    535                     if Key[0] not in Keys:
    536                         Dictionary[Key[0]] = Value
    537                         Keys.append(Key[0])
    538                     else:
    539                         Dictionary[Key[0]].extend(Value)
    540                 else:
    541                     Dictionary[DataType.TAB_INF_DEFINES_MACRO][Key[0]] = Value[0]
    542 
    543     if DefineValues == []:
    544         DefineValues = ['']
    545     if SpecValues == []:
    546         SpecValues = ['']
    547     Dictionary[DataType.TAB_INF_DEFINES_DEFINE] = DefineValues
    548     Dictionary[DataType.TAB_INF_DEFINES_SPEC] = SpecValues
    549 
    550     return True
    551 
    552 ## The content to be parsed
    553 #
    554 # Do pre-check for a file before it is parsed
    555 # Check $()
    556 # Check []
    557 #
    558 # @param FileName:       Used for error report
    559 # @param FileContent:    File content to be parsed
    560 # @param SupSectionTag:  Used for error report
    561 #
    562 def PreCheck(FileName, FileContent, SupSectionTag):
    563     LineNo = 0
    564     IsFailed = False
    565     NewFileContent = ''
    566     for Line in FileContent.splitlines():
    567         LineNo = LineNo + 1
    568         #
    569         # Clean current line
    570         #
    571         Line = CleanString(Line)
    572 
    573         #
    574         # Remove commented line
    575         #
    576         if Line.find(DataType.TAB_COMMA_SPLIT) == 0:
    577             Line = ''
    578         #
    579         # Check $()
    580         #
    581         if Line.find('$') > -1:
    582             if Line.find('$(') < 0 or Line.find(')') < 0:
    583                 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)
    584 
    585         #
    586         # Check []
    587         #
    588         if Line.find('[') > -1 or Line.find(']') > -1:
    589             #
    590             # Only get one '[' or one ']'
    591             #
    592             if not (Line.find('[') > -1 and Line.find(']') > -1):
    593                 EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)
    594 
    595         #
    596         # Regenerate FileContent
    597         #
    598         NewFileContent = NewFileContent + Line + '\r\n'
    599 
    600     if IsFailed:
    601        EdkLogger.error("Parser", FORMAT_INVALID, Line=LineNo, File=FileName, RaiseError=EdkLogger.IsRaiseError)
    602 
    603     return NewFileContent
    604 
    605 ## CheckFileType
    606 #
    607 # Check if the Filename is including ExtName
    608 # Return True if it exists
    609 # Raise a error message if it not exists
    610 #
    611 # @param CheckFilename:      Name of the file to be checked
    612 # @param ExtName:            Ext name of the file to be checked
    613 # @param ContainerFilename:  The container file which describes the file to be checked, used for error report
    614 # @param SectionName:        Used for error report
    615 # @param Line:               The line in container file which defines the file to be checked
    616 #
    617 # @retval True The file type is correct
    618 #
    619 def CheckFileType(CheckFilename, ExtName, ContainerFilename, SectionName, Line, LineNo= -1):
    620     if CheckFilename != '' and CheckFilename != None:
    621         (Root, Ext) = os.path.splitext(CheckFilename)
    622         if Ext.upper() != ExtName.upper():
    623             ContainerFile = open(ContainerFilename, 'r').read()
    624             if LineNo == -1:
    625                 LineNo = GetLineNo(ContainerFile, Line)
    626             ErrorMsg = "Invalid %s. '%s' is found, but '%s' file is needed" % (SectionName, CheckFilename, ExtName)
    627             EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, Line=LineNo,
    628                             File=ContainerFilename, RaiseError=EdkLogger.IsRaiseError)
    629 
    630     return True
    631 
    632 ## CheckFileExist
    633 #
    634 # Check if the file exists
    635 # Return True if it exists
    636 # Raise a error message if it not exists
    637 #
    638 # @param CheckFilename:      Name of the file to be checked
    639 # @param WorkspaceDir:       Current workspace dir
    640 # @param ContainerFilename:  The container file which describes the file to be checked, used for error report
    641 # @param SectionName:        Used for error report
    642 # @param Line:               The line in container file which defines the file to be checked
    643 #
    644 # @retval The file full path if the file exists
    645 #
    646 def CheckFileExist(WorkspaceDir, CheckFilename, ContainerFilename, SectionName, Line, LineNo= -1):
    647     CheckFile = ''
    648     if CheckFilename != '' and CheckFilename != None:
    649         CheckFile = WorkspaceFile(WorkspaceDir, CheckFilename)
    650         if not os.path.isfile(CheckFile):
    651             ContainerFile = open(ContainerFilename, 'r').read()
    652             if LineNo == -1:
    653                 LineNo = GetLineNo(ContainerFile, Line)
    654             ErrorMsg = "Can't find file '%s' defined in section '%s'" % (CheckFile, SectionName)
    655             EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg,
    656                             File=ContainerFilename, Line=LineNo, RaiseError=EdkLogger.IsRaiseError)
    657 
    658     return CheckFile
    659 
    660 ## GetLineNo
    661 #
    662 # Find the index of a line in a file
    663 #
    664 # @param FileContent:  Search scope
    665 # @param Line:         Search key
    666 #
    667 # @retval int  Index of the line
    668 # @retval -1     The line is not found
    669 #
    670 def GetLineNo(FileContent, Line, IsIgnoreComment=True):
    671     LineList = FileContent.splitlines()
    672     for Index in range(len(LineList)):
    673         if LineList[Index].find(Line) > -1:
    674             #
    675             # Ignore statement in comment
    676             #
    677             if IsIgnoreComment:
    678                 if LineList[Index].strip()[0] == DataType.TAB_COMMENT_SPLIT:
    679                     continue
    680             return Index + 1
    681 
    682     return -1
    683 
    684 ## RaiseParserError
    685 #
    686 # Raise a parser error
    687 #
    688 # @param Line:     String which has error
    689 # @param Section:  Used for error report
    690 # @param File:     File which has the string
    691 # @param Format:   Correct format
    692 #
    693 def RaiseParserError(Line, Section, File, Format='', LineNo= -1):
    694     if LineNo == -1:
    695         LineNo = GetLineNo(open(os.path.normpath(File), 'r').read(), Line)
    696     ErrorMsg = "Invalid statement '%s' is found in section '%s'" % (Line, Section)
    697     if Format != '':
    698         Format = "Correct format is " + Format
    699     EdkLogger.error("Parser", PARSER_ERROR, ErrorMsg, File=File, Line=LineNo, ExtraData=Format, RaiseError=EdkLogger.IsRaiseError)
    700 
    701 ## WorkspaceFile
    702 #
    703 # Return a full path with workspace dir
    704 #
    705 # @param WorkspaceDir:  Workspace dir
    706 # @param Filename:      Relative file name
    707 #
    708 # @retval string A full path
    709 #
    710 def WorkspaceFile(WorkspaceDir, Filename):
    711     return mws.join(NormPath(WorkspaceDir), NormPath(Filename))
    712 
    713 ## Split string
    714 #
    715 # Revmove '"' which startswith and endswith string
    716 #
    717 # @param String:  The string need to be splited
    718 #
    719 # @retval String: The string after removed '""'
    720 #
    721 def SplitString(String):
    722     if String.startswith('\"'):
    723         String = String[1:]
    724     if String.endswith('\"'):
    725         String = String[:-1]
    726 
    727     return String
    728 
    729 ## Convert To Sql String
    730 #
    731 # 1. Replace "'" with "''" in each item of StringList
    732 #
    733 # @param StringList:  A list for strings to be converted
    734 #
    735 def ConvertToSqlString(StringList):
    736     return map(lambda s: s.replace("'", "''") , StringList)
    737 
    738 ## Convert To Sql String
    739 #
    740 # 1. Replace "'" with "''" in the String
    741 #
    742 # @param String:  A String to be converted
    743 #
    744 def ConvertToSqlString2(String):
    745     return String.replace("'", "''")
    746 
    747 #
    748 # Remove comment block
    749 #
    750 def RemoveBlockComment(Lines):
    751     IsFindBlockComment = False
    752     IsFindBlockCode = False
    753     ReservedLine = ''
    754     NewLines = []
    755 
    756     for Line in Lines:
    757         Line = Line.strip()
    758         #
    759         # Remove comment block
    760         #
    761         if Line.find(DataType.TAB_COMMENT_EDK_START) > -1:
    762             ReservedLine = GetSplitList(Line, DataType.TAB_COMMENT_EDK_START, 1)[0]
    763             IsFindBlockComment = True
    764         if Line.find(DataType.TAB_COMMENT_EDK_END) > -1:
    765             Line = ReservedLine + GetSplitList(Line, DataType.TAB_COMMENT_EDK_END, 1)[1]
    766             ReservedLine = ''
    767             IsFindBlockComment = False
    768         if IsFindBlockComment:
    769             NewLines.append('')
    770             continue
    771 
    772         NewLines.append(Line)
    773     return NewLines
    774 
    775 #
    776 # Get String of a List
    777 #
    778 def GetStringOfList(List, Split=' '):
    779     if type(List) != type([]):
    780         return List
    781     Str = ''
    782     for Item in List:
    783         Str = Str + Item + Split
    784 
    785     return Str.strip()
    786 
    787 #
    788 # Get HelpTextList from HelpTextClassList
    789 #
    790 def GetHelpTextList(HelpTextClassList):
    791     List = []
    792     if HelpTextClassList:
    793         for HelpText in HelpTextClassList:
    794             if HelpText.String.endswith('\n'):
    795                 HelpText.String = HelpText.String[0: len(HelpText.String) - len('\n')]
    796                 List.extend(HelpText.String.split('\n'))
    797 
    798     return List
    799 
    800 def StringToArray(String):
    801     if isinstance(String, unicode):
    802         if len(unicode) == 0:
    803             return "{0x00, 0x00}"
    804         return "{%s, 0x00, 0x00}" % ", ".join(["0x%02x, 0x00" % ord(C) for C in String])
    805     elif String.startswith('L"'):
    806         if String == "L\"\"":
    807             return "{0x00, 0x00}"
    808         else:
    809             return "{%s, 0x00, 0x00}" % ", ".join(["0x%02x, 0x00" % ord(C) for C in String[2:-1]])
    810     elif String.startswith('"'):
    811         if String == "\"\"":
    812             return "{0x00,0x00}"
    813         else:
    814             StringLen = len(String[1:-1])
    815             if StringLen % 2:
    816                 return "{%s, 0x00}" % ", ".join(["0x%02x" % ord(C) for C in String[1:-1]])
    817             else:
    818                 return "{%s, 0x00,0x00}" % ", ".join(["0x%02x" % ord(C) for C in String[1:-1]])
    819     elif String.startswith('{'):
    820         StringLen = len(String.split(","))
    821         if StringLen % 2:
    822             return "{%s, 0x00}" % ", ".join([ C for C in String[1:-1].split(',')])
    823         else:
    824             return "{%s}" % ", ".join([ C for C in String[1:-1].split(',')])
    825         
    826     else:
    827         if len(String.split()) % 2:
    828             return '{%s, 0}' % ', '.join(String.split())
    829         else:
    830             return '{%s, 0,0}' % ', '.join(String.split())
    831 
    832 def StringArrayLength(String):
    833     if isinstance(String, unicode):
    834         return (len(String) + 1) * 2 + 1;
    835     elif String.startswith('L"'):
    836         return (len(String) - 3 + 1) * 2
    837     elif String.startswith('"'):
    838         return (len(String) - 2 + 1)
    839     else:
    840         return len(String.split()) + 1
    841 
    842 def RemoveDupOption(OptionString, Which="/I", Against=None):
    843     OptionList = OptionString.split()
    844     ValueList = []
    845     if Against:
    846         ValueList += Against
    847     for Index in range(len(OptionList)):
    848         Opt = OptionList[Index]
    849         if not Opt.startswith(Which):
    850             continue
    851         if len(Opt) > len(Which):
    852             Val = Opt[len(Which):]
    853         else:
    854             Val = ""
    855         if Val in ValueList:
    856             OptionList[Index] = ""
    857         else:
    858             ValueList.append(Val)
    859     return " ".join(OptionList)
    860 
    861 ##

    862 #

    863 # This acts like the main() function for the script, unless it is 'import'ed into another

    864 # script.

    865 #

    866 if __name__ == '__main__':
    867     pass
    868 
    869