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#
17import re
18import DataType
19import Common.LongFilePathOs as os
20import string
21import EdkLogger as EdkLogger
22
23import GlobalData
24from BuildToolError import *
25from CommonDataClass.Exceptions import *
26from Common.LongFilePathSupport import OpenLongFilePath as open
27from Common.MultipleWorkspace import MultipleWorkspace as mws
28
29gHexVerPatt = re.compile('0x[a-f0-9]{4}[a-f0-9]{4}$', re.IGNORECASE)
30gHumanReadableVerPatt = 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#
44def 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#
89def 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#
101def 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#
121def 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#
145def 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#
164def 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#
186def 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#
210def 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#
240def 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#
261def 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#
295def 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#
330def 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#
387def 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#
427def 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#
448def 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#
463def 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#
496def 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#
562def 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#
619def 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#
646def 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#
670def 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#
693def 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#
710def 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#
721def 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#
735def 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#
744def ConvertToSqlString2(String):
745    return String.replace("'", "''")
746
747#
748# Remove comment block
749#
750def 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#
778def 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#
790def 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
800def 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
832def 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
842def 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#
866if __name__ == '__main__':
867    pass
868
869