1## @file
2# This file is used to be the c coding style checking of ECC tool
3#
4# Copyright (c) 2009 - 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
14import sys
15import Common.LongFilePathOs as os
16import re
17import string
18import CodeFragmentCollector
19import FileProfile
20from CommonDataClass import DataClass
21import Database
22from Common import EdkLogger
23from EccToolError import *
24import EccGlobalData
25import MetaDataParser
26
27IncludeFileListDict = {}
28AllIncludeFileListDict = {}
29IncludePathListDict = {}
30ComplexTypeDict = {}
31SUDict = {}
32IgnoredKeywordList = ['EFI_ERROR']
33
34def GetIgnoredDirListPattern():
35    skipList = list(EccGlobalData.gConfig.SkipDirList) + ['.svn']
36    DirString = string.join(skipList, '|')
37    p = re.compile(r'.*[\\/](?:%s)[\\/]?.*' % DirString)
38    return p
39
40def GetFuncDeclPattern():
41    p = re.compile(r'(?:EFIAPI|EFI_BOOT_SERVICE|EFI_RUNTIME_SERVICE)?\s*[_\w]+\s*\(.*\)$', re.DOTALL)
42    return p
43
44def GetArrayPattern():
45    p = re.compile(r'[_\w]*\s*[\[.*\]]+')
46    return p
47
48def GetTypedefFuncPointerPattern():
49    p = re.compile('[_\w\s]*\([\w\s]*\*+\s*[_\w]+\s*\)\s*\(.*\)', re.DOTALL)
50    return p
51
52def GetDB():
53    return EccGlobalData.gDb
54
55def GetConfig():
56    return EccGlobalData.gConfig
57
58def PrintErrorMsg(ErrorType, Msg, TableName, ItemId):
59    Msg = Msg.replace('\n', '').replace('\r', '')
60    MsgPartList = Msg.split()
61    Msg = ''
62    for Part in MsgPartList:
63        Msg += Part
64        Msg += ' '
65    GetDB().TblReport.Insert(ErrorType, OtherMsg=Msg, BelongsToTable=TableName, BelongsToItem=ItemId)
66
67def GetIdType(Str):
68    Type = DataClass.MODEL_UNKNOWN
69    Str = Str.replace('#', '# ')
70    List = Str.split()
71    if List[1] == 'include':
72        Type = DataClass.MODEL_IDENTIFIER_INCLUDE
73    elif List[1] == 'define':
74        Type = DataClass.MODEL_IDENTIFIER_MACRO_DEFINE
75    elif List[1] == 'ifdef':
76        Type = DataClass.MODEL_IDENTIFIER_MACRO_IFDEF
77    elif List[1] == 'ifndef':
78        Type = DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF
79    elif List[1] == 'endif':
80        Type = DataClass.MODEL_IDENTIFIER_MACRO_ENDIF
81    elif List[1] == 'pragma':
82        Type = DataClass.MODEL_IDENTIFIER_MACRO_PROGMA
83    else:
84        Type = DataClass.MODEL_UNKNOWN
85    return Type
86
87def SuOccurInTypedef (Su, TdList):
88    for Td in TdList:
89        if Su.StartPos[0] == Td.StartPos[0] and Su.EndPos[0] == Td.EndPos[0]:
90            return True
91    return False
92
93def GetIdentifierList():
94    IdList = []
95    for comment in FileProfile.CommentList:
96        IdComment = DataClass.IdentifierClass(-1, '', '', '', comment.Content, DataClass.MODEL_IDENTIFIER_COMMENT, -1, -1, comment.StartPos[0], comment.StartPos[1], comment.EndPos[0], comment.EndPos[1])
97        IdList.append(IdComment)
98
99    for pp in FileProfile.PPDirectiveList:
100        Type = GetIdType(pp.Content)
101        IdPP = DataClass.IdentifierClass(-1, '', '', '', pp.Content, Type, -1, -1, pp.StartPos[0], pp.StartPos[1], pp.EndPos[0], pp.EndPos[1])
102        IdList.append(IdPP)
103
104    for pe in FileProfile.PredicateExpressionList:
105        IdPE = DataClass.IdentifierClass(-1, '', '', '', pe.Content, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION, -1, -1, pe.StartPos[0], pe.StartPos[1], pe.EndPos[0], pe.EndPos[1])
106        IdList.append(IdPE)
107
108    FuncDeclPattern = GetFuncDeclPattern()
109    ArrayPattern = GetArrayPattern()
110    for var in FileProfile.VariableDeclarationList:
111        DeclText = var.Declarator.lstrip()
112        FuncPointerPattern = GetTypedefFuncPointerPattern()
113        if FuncPointerPattern.match(DeclText):
114            continue
115        VarNameStartLine = var.NameStartPos[0]
116        VarNameStartColumn = var.NameStartPos[1]
117        FirstChar = DeclText[0]
118        while not FirstChar.isalpha() and FirstChar != '_':
119            if FirstChar == '*':
120                var.Modifier += '*'
121                VarNameStartColumn += 1
122                DeclText = DeclText.lstrip('*')
123            elif FirstChar == '\r':
124                DeclText = DeclText.lstrip('\r\n').lstrip('\r')
125                VarNameStartLine += 1
126                VarNameStartColumn = 0
127            elif FirstChar == '\n':
128                DeclText = DeclText.lstrip('\n')
129                VarNameStartLine += 1
130                VarNameStartColumn = 0
131            elif FirstChar == ' ':
132                DeclText = DeclText.lstrip(' ')
133                VarNameStartColumn += 1
134            elif FirstChar == '\t':
135                DeclText = DeclText.lstrip('\t')
136                VarNameStartColumn += 8
137            else:
138                DeclText = DeclText[1:]
139                VarNameStartColumn += 1
140            FirstChar = DeclText[0]
141
142        var.Declarator = DeclText
143        if FuncDeclPattern.match(var.Declarator):
144            DeclSplitList = var.Declarator.split('(')
145            FuncName = DeclSplitList[0].strip()
146            FuncNamePartList = FuncName.split()
147            if len(FuncNamePartList) > 1:
148                FuncName = FuncNamePartList[-1].strip()
149                NameStart = DeclSplitList[0].rfind(FuncName)
150                var.Declarator = var.Declarator[NameStart:]
151                if NameStart > 0:
152                    var.Modifier += ' ' + DeclSplitList[0][0:NameStart]
153                    Index = 0
154                    PreChar = ''
155                    while Index < NameStart:
156                        FirstChar = DeclSplitList[0][Index]
157                        if DeclSplitList[0][Index:].startswith('EFIAPI'):
158                            Index += 6
159                            VarNameStartColumn += 6
160                            PreChar = ''
161                            continue
162                        elif FirstChar == '\r':
163                            Index += 1
164                            VarNameStartLine += 1
165                            VarNameStartColumn = 0
166                        elif FirstChar == '\n':
167                            Index += 1
168                            if PreChar != '\r':
169                                VarNameStartLine += 1
170                                VarNameStartColumn = 0
171                        elif FirstChar == ' ':
172                            Index += 1
173                            VarNameStartColumn += 1
174                        elif FirstChar == '\t':
175                            Index += 1
176                            VarNameStartColumn += 8
177                        else:
178                            Index += 1
179                            VarNameStartColumn += 1
180                        PreChar = FirstChar
181            IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', var.Declarator, FuncName, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, -1, -1, var.StartPos[0], var.StartPos[1], VarNameStartLine, VarNameStartColumn)
182            IdList.append(IdVar)
183            continue
184
185        if var.Declarator.find('{') == -1:
186            for decl in var.Declarator.split(','):
187                DeclList = decl.split('=')
188                Name = DeclList[0].strip()
189                if ArrayPattern.match(Name):
190                    LSBPos = var.Declarator.find('[')
191                    var.Modifier += ' ' + Name[LSBPos:]
192                    Name = Name[0:LSBPos]
193
194                IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', Name, (len(DeclList) > 1 and [DeclList[1]]or [''])[0], DataClass.MODEL_IDENTIFIER_VARIABLE, -1, -1, var.StartPos[0], var.StartPos[1], VarNameStartLine, VarNameStartColumn)
195                IdList.append(IdVar)
196        else:
197            DeclList = var.Declarator.split('=')
198            Name = DeclList[0].strip()
199            if ArrayPattern.match(Name):
200                LSBPos = var.Declarator.find('[')
201                var.Modifier += ' ' + Name[LSBPos:]
202                Name = Name[0:LSBPos]
203            IdVar = DataClass.IdentifierClass(-1, var.Modifier, '', Name, (len(DeclList) > 1 and [DeclList[1]]or [''])[0], DataClass.MODEL_IDENTIFIER_VARIABLE, -1, -1, var.StartPos[0], var.StartPos[1], VarNameStartLine, VarNameStartColumn)
204            IdList.append(IdVar)
205
206    for enum in FileProfile.EnumerationDefinitionList:
207        LBPos = enum.Content.find('{')
208        RBPos = enum.Content.find('}')
209        Name = enum.Content[4:LBPos].strip()
210        Value = enum.Content[LBPos + 1:RBPos]
211        IdEnum = DataClass.IdentifierClass(-1, '', '', Name, Value, DataClass.MODEL_IDENTIFIER_ENUMERATE, -1, -1, enum.StartPos[0], enum.StartPos[1], enum.EndPos[0], enum.EndPos[1])
212        IdList.append(IdEnum)
213
214    for su in FileProfile.StructUnionDefinitionList:
215        if SuOccurInTypedef(su, FileProfile.TypedefDefinitionList):
216            continue
217        Type = DataClass.MODEL_IDENTIFIER_STRUCTURE
218        SkipLen = 6
219        if su.Content.startswith('union'):
220            Type = DataClass.MODEL_IDENTIFIER_UNION
221            SkipLen = 5
222        LBPos = su.Content.find('{')
223        RBPos = su.Content.find('}')
224        if LBPos == -1 or RBPos == -1:
225            Name = su.Content[SkipLen:].strip()
226            Value = ''
227        else:
228            Name = su.Content[SkipLen:LBPos].strip()
229            Value = su.Content[LBPos:RBPos + 1]
230        IdPE = DataClass.IdentifierClass(-1, '', '', Name, Value, Type, -1, -1, su.StartPos[0], su.StartPos[1], su.EndPos[0], su.EndPos[1])
231        IdList.append(IdPE)
232
233    TdFuncPointerPattern = GetTypedefFuncPointerPattern()
234    for td in FileProfile.TypedefDefinitionList:
235        Modifier = ''
236        Name = td.ToType
237        Value = td.FromType
238        if TdFuncPointerPattern.match(td.ToType):
239            Modifier = td.FromType
240            LBPos = td.ToType.find('(')
241            TmpStr = td.ToType[LBPos + 1:].strip()
242            StarPos = TmpStr.find('*')
243            if StarPos != -1:
244                Modifier += ' ' + TmpStr[0:StarPos]
245            while TmpStr[StarPos] == '*':
246#                Modifier += ' ' + '*'
247                StarPos += 1
248            TmpStr = TmpStr[StarPos:].strip()
249            RBPos = TmpStr.find(')')
250            Name = TmpStr[0:RBPos]
251            Value = 'FP' + TmpStr[RBPos + 1:]
252        else:
253            while Name.startswith('*'):
254                Value += ' ' + '*'
255                Name = Name.lstrip('*').strip()
256
257        if Name.find('[') != -1:
258            LBPos = Name.find('[')
259            RBPos = Name.rfind(']')
260            Value += Name[LBPos : RBPos + 1]
261            Name = Name[0 : LBPos]
262
263        IdTd = DataClass.IdentifierClass(-1, Modifier, '', Name, Value, DataClass.MODEL_IDENTIFIER_TYPEDEF, -1, -1, td.StartPos[0], td.StartPos[1], td.EndPos[0], td.EndPos[1])
264        IdList.append(IdTd)
265
266    for funcCall in FileProfile.FunctionCallingList:
267        IdFC = DataClass.IdentifierClass(-1, '', '', funcCall.FuncName, funcCall.ParamList, DataClass.MODEL_IDENTIFIER_FUNCTION_CALLING, -1, -1, funcCall.StartPos[0], funcCall.StartPos[1], funcCall.EndPos[0], funcCall.EndPos[1])
268        IdList.append(IdFC)
269    return IdList
270
271def StripNonAlnumChars(Str):
272    StrippedStr = ''
273    for Char in Str:
274        if Char.isalnum():
275            StrippedStr += Char
276    return StrippedStr
277
278def GetParamList(FuncDeclarator, FuncNameLine=0, FuncNameOffset=0):
279    FuncDeclarator = StripComments(FuncDeclarator)
280    ParamIdList = []
281    #DeclSplitList = FuncDeclarator.split('(')
282    LBPos = FuncDeclarator.find('(')
283    #if len(DeclSplitList) < 2:
284    if LBPos == -1:
285        return ParamIdList
286    #FuncName = DeclSplitList[0]
287    FuncName = FuncDeclarator[0:LBPos]
288    #ParamStr = DeclSplitList[1].rstrip(')')
289    ParamStr = FuncDeclarator[LBPos + 1:].rstrip(')')
290    LineSkipped = 0
291    OffsetSkipped = 0
292    TailChar = FuncName[-1]
293    while not TailChar.isalpha() and TailChar != '_':
294
295        if TailChar == '\n':
296            FuncName = FuncName.rstrip('\r\n').rstrip('\n')
297            LineSkipped += 1
298            OffsetSkipped = 0
299        elif TailChar == '\r':
300            FuncName = FuncName.rstrip('\r')
301            LineSkipped += 1
302            OffsetSkipped = 0
303        elif TailChar == ' ':
304            FuncName = FuncName.rstrip(' ')
305            OffsetSkipped += 1
306        elif TailChar == '\t':
307            FuncName = FuncName.rstrip('\t')
308            OffsetSkipped += 8
309        else:
310            FuncName = FuncName[:-1]
311        TailChar = FuncName[-1]
312
313    OffsetSkipped += 1 #skip '('
314
315    for p in ParamStr.split(','):
316        ListP = p.split()
317        if len(ListP) == 0:
318            continue
319        ParamName = ListP[-1]
320        DeclText = ParamName.strip()
321        RightSpacePos = p.rfind(ParamName)
322        ParamModifier = p[0:RightSpacePos]
323        if ParamName == 'OPTIONAL':
324            if ParamModifier == '':
325                ParamModifier += ' ' + 'OPTIONAL'
326                DeclText = ''
327            else:
328                ParamName = ListP[-2]
329                DeclText = ParamName.strip()
330                RightSpacePos = p.rfind(ParamName)
331                ParamModifier = p[0:RightSpacePos]
332                ParamModifier += 'OPTIONAL'
333        while DeclText.startswith('*'):
334            ParamModifier += ' ' + '*'
335            DeclText = DeclText.lstrip('*').strip()
336        ParamName = DeclText
337        # ignore array length if exists.
338        LBIndex = ParamName.find('[')
339        if LBIndex != -1:
340            ParamName = ParamName[0:LBIndex]
341
342        Start = RightSpacePos
343        Index = 0
344        PreChar = ''
345        while Index < Start:
346            FirstChar = p[Index]
347
348            if FirstChar == '\r':
349                Index += 1
350                LineSkipped += 1
351                OffsetSkipped = 0
352            elif FirstChar == '\n':
353                Index += 1
354                if PreChar != '\r':
355                    LineSkipped += 1
356                    OffsetSkipped = 0
357            elif FirstChar == ' ':
358                Index += 1
359                OffsetSkipped += 1
360            elif FirstChar == '\t':
361                Index += 1
362                OffsetSkipped += 8
363            else:
364                Index += 1
365                OffsetSkipped += 1
366            PreChar = FirstChar
367
368        ParamBeginLine = FuncNameLine + LineSkipped
369        ParamBeginOffset = FuncNameOffset + OffsetSkipped
370
371        Index = Start + len(ParamName)
372        PreChar = ''
373        while Index < len(p):
374            FirstChar = p[Index]
375
376            if FirstChar == '\r':
377                Index += 1
378                LineSkipped += 1
379                OffsetSkipped = 0
380            elif FirstChar == '\n':
381                Index += 1
382                if PreChar != '\r':
383                    LineSkipped += 1
384                    OffsetSkipped = 0
385            elif FirstChar == ' ':
386                Index += 1
387                OffsetSkipped += 1
388            elif FirstChar == '\t':
389                Index += 1
390                OffsetSkipped += 8
391            else:
392                Index += 1
393                OffsetSkipped += 1
394            PreChar = FirstChar
395
396        ParamEndLine = FuncNameLine + LineSkipped
397        ParamEndOffset = FuncNameOffset + OffsetSkipped
398        if ParamName != '...':
399            ParamName = StripNonAlnumChars(ParamName)
400        IdParam = DataClass.IdentifierClass(-1, ParamModifier, '', ParamName, '', DataClass.MODEL_IDENTIFIER_PARAMETER, -1, -1, ParamBeginLine, ParamBeginOffset, ParamEndLine, ParamEndOffset)
401        ParamIdList.append(IdParam)
402
403        OffsetSkipped += 1 #skip ','
404
405    return ParamIdList
406
407def GetFunctionList():
408    FuncObjList = []
409    for FuncDef in FileProfile.FunctionDefinitionList:
410        ParamIdList = []
411        DeclText = FuncDef.Declarator.lstrip()
412        FuncNameStartLine = FuncDef.NamePos[0]
413        FuncNameStartColumn = FuncDef.NamePos[1]
414        FirstChar = DeclText[0]
415        while not FirstChar.isalpha() and FirstChar != '_':
416            if FirstChar == '*':
417                FuncDef.Modifier += '*'
418                FuncNameStartColumn += 1
419                DeclText = DeclText.lstrip('*')
420            elif FirstChar == '\r':
421                DeclText = DeclText.lstrip('\r\n').lstrip('\r')
422                FuncNameStartLine += 1
423                FuncNameStartColumn = 0
424            elif FirstChar == '\n':
425                DeclText = DeclText.lstrip('\n')
426                FuncNameStartLine += 1
427                FuncNameStartColumn = 0
428            elif FirstChar == ' ':
429                DeclText = DeclText.lstrip(' ')
430                FuncNameStartColumn += 1
431            elif FirstChar == '\t':
432                DeclText = DeclText.lstrip('\t')
433                FuncNameStartColumn += 8
434            else:
435                DeclText = DeclText[1:]
436                FuncNameStartColumn += 1
437            FirstChar = DeclText[0]
438
439        FuncDef.Declarator = DeclText
440        DeclSplitList = FuncDef.Declarator.split('(')
441        if len(DeclSplitList) < 2:
442            continue
443
444        FuncName = DeclSplitList[0]
445        FuncNamePartList = FuncName.split()
446        if len(FuncNamePartList) > 1:
447            FuncName = FuncNamePartList[-1]
448            NameStart = DeclSplitList[0].rfind(FuncName)
449            if NameStart > 0:
450                FuncDef.Modifier += ' ' + DeclSplitList[0][0:NameStart]
451                Index = 0
452                PreChar = ''
453                while Index < NameStart:
454                    FirstChar = DeclSplitList[0][Index]
455                    if DeclSplitList[0][Index:].startswith('EFIAPI'):
456                        Index += 6
457                        FuncNameStartColumn += 6
458                        PreChar = ''
459                        continue
460                    elif FirstChar == '\r':
461                        Index += 1
462                        FuncNameStartLine += 1
463                        FuncNameStartColumn = 0
464                    elif FirstChar == '\n':
465                        Index += 1
466                        if PreChar != '\r':
467                            FuncNameStartLine += 1
468                            FuncNameStartColumn = 0
469                    elif FirstChar == ' ':
470                        Index += 1
471                        FuncNameStartColumn += 1
472                    elif FirstChar == '\t':
473                        Index += 1
474                        FuncNameStartColumn += 8
475                    else:
476                        Index += 1
477                        FuncNameStartColumn += 1
478                    PreChar = FirstChar
479
480        FuncObj = DataClass.FunctionClass(-1, FuncDef.Declarator, FuncDef.Modifier, FuncName.strip(), '', FuncDef.StartPos[0], FuncDef.StartPos[1], FuncDef.EndPos[0], FuncDef.EndPos[1], FuncDef.LeftBracePos[0], FuncDef.LeftBracePos[1], -1, ParamIdList, [], FuncNameStartLine, FuncNameStartColumn)
481        FuncObjList.append(FuncObj)
482
483    return FuncObjList
484
485def GetFileModificationTimeFromDB(FullFileName):
486    TimeValue = 0.0
487    Db = GetDB()
488    SqlStatement = """ select TimeStamp
489                       from File
490                       where FullPath = \'%s\'
491                   """ % (FullFileName)
492    ResultSet = Db.TblFile.Exec(SqlStatement)
493    for Result in ResultSet:
494        TimeValue = Result[0]
495    return TimeValue
496
497def CollectSourceCodeDataIntoDB(RootDir):
498    FileObjList = []
499    tuple = os.walk(RootDir)
500    IgnoredPattern = GetIgnoredDirListPattern()
501    ParseErrorFileList = []
502
503    for dirpath, dirnames, filenames in tuple:
504        if IgnoredPattern.match(dirpath.upper()):
505            continue
506
507        for Dir in dirnames:
508            Dirname = os.path.join(dirpath, Dir)
509            if os.path.islink(Dirname):
510                Dirname = os.path.realpath(Dirname)
511                if os.path.isdir(Dirname):
512                    # symlinks to directories are treated as directories
513                    dirnames.remove(Dir)
514                    dirnames.append(Dirname)
515
516        for f in filenames:
517            if f.lower() in EccGlobalData.gConfig.SkipFileList:
518                continue
519            collector = None
520            FullName = os.path.normpath(os.path.join(dirpath, f))
521            model = DataClass.MODEL_FILE_OTHERS
522            if os.path.splitext(f)[1] in ('.h', '.c'):
523                EdkLogger.info("Parsing " + FullName)
524                model = f.endswith('c') and DataClass.MODEL_FILE_C or DataClass.MODEL_FILE_H
525                collector = CodeFragmentCollector.CodeFragmentCollector(FullName)
526                try:
527                    collector.ParseFile()
528                except UnicodeError:
529                    ParseErrorFileList.append(FullName)
530                    collector.CleanFileProfileBuffer()
531                    collector.ParseFileWithClearedPPDirective()
532#                collector.PrintFragments()
533            BaseName = os.path.basename(f)
534            DirName = os.path.dirname(FullName)
535            Ext = os.path.splitext(f)[1].lstrip('.')
536            ModifiedTime = os.path.getmtime(FullName)
537            FileObj = DataClass.FileClass(-1, BaseName, Ext, DirName, FullName, model, ModifiedTime, GetFunctionList(), GetIdentifierList(), [])
538            FileObjList.append(FileObj)
539            if collector:
540                collector.CleanFileProfileBuffer()
541
542    if len(ParseErrorFileList) > 0:
543        EdkLogger.info("Found unrecoverable error during parsing:\n\t%s\n" % "\n\t".join(ParseErrorFileList))
544
545    Db = GetDB()
546    for file in FileObjList:
547        if file.ExtName.upper() not in ['INF', 'DEC', 'DSC', 'FDF']:
548            Db.InsertOneFile(file)
549
550    Db.UpdateIdentifierBelongsToFunction()
551
552def GetTableID(FullFileName, ErrorMsgList=None):
553    if ErrorMsgList == None:
554        ErrorMsgList = []
555
556    Db = GetDB()
557    SqlStatement = """ select ID
558                       from File
559                       where FullPath like '%s'
560                   """ % FullFileName
561    ResultSet = Db.TblFile.Exec(SqlStatement)
562
563    FileID = -1
564    for Result in ResultSet:
565        if FileID != -1:
566            ErrorMsgList.append('Duplicate file ID found in DB for file %s' % FullFileName)
567            return - 2
568        FileID = Result[0]
569    if FileID == -1:
570        ErrorMsgList.append('NO file ID found in DB for file %s' % FullFileName)
571        return - 1
572    return FileID
573
574def GetIncludeFileList(FullFileName):
575    if os.path.splitext(FullFileName)[1].upper() not in ('.H'):
576        return []
577    IFList = IncludeFileListDict.get(FullFileName)
578    if IFList != None:
579        return IFList
580
581    FileID = GetTableID(FullFileName)
582    if FileID < 0:
583        return []
584
585    Db = GetDB()
586    FileTable = 'Identifier' + str(FileID)
587    SqlStatement = """ select Value
588                       from %s
589                       where Model = %d
590                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_INCLUDE)
591    ResultSet = Db.TblFile.Exec(SqlStatement)
592    IncludeFileListDict[FullFileName] = ResultSet
593    return ResultSet
594
595def GetFullPathOfIncludeFile(Str, IncludePathList):
596    for IncludePath in IncludePathList:
597        FullPath = os.path.join(IncludePath, Str)
598        FullPath = os.path.normpath(FullPath)
599        if os.path.exists(FullPath):
600            return FullPath
601    return None
602
603def GetAllIncludeFiles(FullFileName):
604    if AllIncludeFileListDict.get(FullFileName) != None:
605        return AllIncludeFileListDict.get(FullFileName)
606
607    FileDirName = os.path.dirname(FullFileName)
608    IncludePathList = IncludePathListDict.get(FileDirName)
609    if IncludePathList == None:
610        IncludePathList = MetaDataParser.GetIncludeListOfFile(EccGlobalData.gWorkspace, FullFileName, GetDB())
611        if FileDirName not in IncludePathList:
612            IncludePathList.insert(0, FileDirName)
613        IncludePathListDict[FileDirName] = IncludePathList
614    IncludeFileQueue = []
615    for IncludeFile in GetIncludeFileList(FullFileName):
616        FileName = IncludeFile[0].lstrip('#').strip()
617        FileName = FileName.lstrip('include').strip()
618        FileName = FileName.strip('\"')
619        FileName = FileName.lstrip('<').rstrip('>').strip()
620        FullPath = GetFullPathOfIncludeFile(FileName, IncludePathList)
621        if FullPath != None:
622            IncludeFileQueue.append(FullPath)
623
624    i = 0
625    while i < len(IncludeFileQueue):
626        for IncludeFile in GetIncludeFileList(IncludeFileQueue[i]):
627            FileName = IncludeFile[0].lstrip('#').strip()
628            FileName = FileName.lstrip('include').strip()
629            FileName = FileName.strip('\"')
630            FileName = FileName.lstrip('<').rstrip('>').strip()
631            FullPath = GetFullPathOfIncludeFile(FileName, IncludePathList)
632            if FullPath != None and FullPath not in IncludeFileQueue:
633                IncludeFileQueue.insert(i + 1, FullPath)
634        i += 1
635
636    AllIncludeFileListDict[FullFileName] = IncludeFileQueue
637    return IncludeFileQueue
638
639def GetPredicateListFromPredicateExpStr(PES):
640
641    PredicateList = []
642    i = 0
643    PredicateBegin = 0
644    #PredicateEnd = 0
645    LogicOpPos = -1
646    p = GetFuncDeclPattern()
647    while i < len(PES) - 1:
648        if (PES[i].isalnum() or PES[i] == '_' or PES[i] == '*') and LogicOpPos > PredicateBegin:
649            PredicateBegin = i
650        if (PES[i] == '&' and PES[i + 1] == '&') or (PES[i] == '|' and PES[i + 1] == '|'):
651            LogicOpPos = i
652            Exp = PES[PredicateBegin:i].strip()
653            # Exp may contain '.' or '->'
654            TmpExp = Exp.replace('.', '').replace('->', '')
655            if p.match(TmpExp):
656                PredicateList.append(Exp)
657            else:
658                PredicateList.append(Exp.rstrip(';').rstrip(')').strip())
659        i += 1
660
661    if PredicateBegin > LogicOpPos:
662        while PredicateBegin < len(PES):
663            if PES[PredicateBegin].isalnum() or PES[PredicateBegin] == '_' or PES[PredicateBegin] == '*':
664                break
665            PredicateBegin += 1
666        Exp = PES[PredicateBegin:len(PES)].strip()
667        # Exp may contain '.' or '->'
668        TmpExp = Exp.replace('.', '').replace('->', '')
669        if p.match(TmpExp):
670            PredicateList.append(Exp)
671        else:
672            PredicateList.append(Exp.rstrip(';').rstrip(')').strip())
673    return PredicateList
674
675def GetCNameList(Lvalue, StarList=[]):
676    Lvalue += ' '
677    i = 0
678    SearchBegin = 0
679    VarStart = -1
680    VarEnd = -1
681    VarList = []
682
683    while SearchBegin < len(Lvalue):
684        while i < len(Lvalue):
685            if Lvalue[i].isalnum() or Lvalue[i] == '_':
686                if VarStart == -1:
687                    VarStart = i
688                VarEnd = i
689                i += 1
690            elif VarEnd != -1:
691                VarList.append(Lvalue[VarStart:VarEnd + 1])
692                i += 1
693                break
694            else:
695                if VarStart == -1 and Lvalue[i] == '*':
696                    StarList.append('*')
697                i += 1
698        if VarEnd == -1:
699            break
700
701
702        DotIndex = Lvalue[VarEnd:].find('.')
703        ArrowIndex = Lvalue[VarEnd:].find('->')
704        if DotIndex == -1 and ArrowIndex == -1:
705            break
706        elif DotIndex == -1 and ArrowIndex != -1:
707            SearchBegin = VarEnd + ArrowIndex
708        elif ArrowIndex == -1 and DotIndex != -1:
709            SearchBegin = VarEnd + DotIndex
710        else:
711            SearchBegin = VarEnd + ((DotIndex < ArrowIndex) and DotIndex or ArrowIndex)
712
713        i = SearchBegin
714        VarStart = -1
715        VarEnd = -1
716
717    return VarList
718
719def SplitPredicateByOp(Str, Op, IsFuncCalling=False):
720
721    Name = Str.strip()
722    Value = None
723
724    if IsFuncCalling:
725        Index = 0
726        LBFound = False
727        UnmatchedLBCount = 0
728        while Index < len(Str):
729            while not LBFound and Str[Index] != '_' and not Str[Index].isalnum():
730                Index += 1
731
732            while not LBFound and (Str[Index].isalnum() or Str[Index] == '_'):
733                Index += 1
734            # maybe type-cast at the begining, skip it.
735            RemainingStr = Str[Index:].lstrip()
736            if RemainingStr.startswith(')') and not LBFound:
737                Index += 1
738                continue
739
740            if RemainingStr.startswith('(') and not LBFound:
741                LBFound = True
742
743            if Str[Index] == '(':
744                UnmatchedLBCount += 1
745                Index += 1
746                continue
747
748            if Str[Index] == ')':
749                UnmatchedLBCount -= 1
750                Index += 1
751                if UnmatchedLBCount == 0:
752                    break
753                continue
754
755            Index += 1
756
757        if UnmatchedLBCount > 0:
758            return [Name]
759
760        IndexInRemainingStr = Str[Index:].find(Op)
761        if IndexInRemainingStr == -1:
762            return [Name]
763
764        Name = Str[0:Index + IndexInRemainingStr].strip()
765        Value = Str[Index + IndexInRemainingStr + len(Op):].strip().strip(')')
766        return [Name, Value]
767
768    TmpStr = Str.rstrip(';').rstrip(')')
769    while True:
770        Index = TmpStr.rfind(Op)
771        if Index == -1:
772            return [Name]
773
774        if Str[Index - 1].isalnum() or Str[Index - 1].isspace() or Str[Index - 1] == ')' or Str[Index - 1] == ']':
775            Name = Str[0:Index].strip()
776            Value = Str[Index + len(Op):].strip()
777            return [Name, Value]
778
779        TmpStr = Str[0:Index - 1]
780
781def SplitPredicateStr(Str):
782
783    Str = Str.lstrip('(')
784    IsFuncCalling = False
785    p = GetFuncDeclPattern()
786    TmpStr = Str.replace('.', '').replace('->', '')
787    if p.match(TmpStr):
788        IsFuncCalling = True
789
790    PredPartList = SplitPredicateByOp(Str, '==', IsFuncCalling)
791    if len(PredPartList) > 1:
792        return [PredPartList, '==']
793
794    PredPartList = SplitPredicateByOp(Str, '!=', IsFuncCalling)
795    if len(PredPartList) > 1:
796        return [PredPartList, '!=']
797
798    PredPartList = SplitPredicateByOp(Str, '>=', IsFuncCalling)
799    if len(PredPartList) > 1:
800        return [PredPartList, '>=']
801
802    PredPartList = SplitPredicateByOp(Str, '<=', IsFuncCalling)
803    if len(PredPartList) > 1:
804        return [PredPartList, '<=']
805
806    PredPartList = SplitPredicateByOp(Str, '>', IsFuncCalling)
807    if len(PredPartList) > 1:
808        return [PredPartList, '>']
809
810    PredPartList = SplitPredicateByOp(Str, '<', IsFuncCalling)
811    if len(PredPartList) > 1:
812        return [PredPartList, '<']
813
814    return [[Str, None], None]
815
816def GetFuncContainsPE(ExpLine, ResultSet):
817    for Result in ResultSet:
818        if Result[0] < ExpLine and Result[1] > ExpLine:
819            return Result
820    return None
821
822def PatternInModifier(Modifier, SubStr):
823    PartList = Modifier.split()
824    for Part in PartList:
825        if Part == SubStr:
826            return True
827    return False
828
829def GetDataTypeFromModifier(ModifierStr):
830    MList = ModifierStr.split()
831    ReturnType = ''
832    for M in MList:
833        if M in EccGlobalData.gConfig.ModifierList:
834            continue
835        # remove array sufix
836        if M.startswith('[') or M.endswith(']'):
837            continue
838        ReturnType += M + ' '
839
840    ReturnType = ReturnType.strip()
841    if len(ReturnType) == 0:
842        ReturnType = 'VOID'
843    return ReturnType
844
845def DiffModifier(Str1, Str2):
846    PartList1 = Str1.split()
847    PartList2 = Str2.split()
848    if PartList1 == PartList2:
849        return False
850    else:
851        return True
852
853def GetTypedefDict(FullFileName):
854
855    Dict = ComplexTypeDict.get(FullFileName)
856    if Dict != None:
857        return Dict
858
859    FileID = GetTableID(FullFileName)
860    FileTable = 'Identifier' + str(FileID)
861    Db = GetDB()
862    SqlStatement = """ select Modifier, Name, Value, ID
863                       from %s
864                       where Model = %d
865                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
866    ResultSet = Db.TblFile.Exec(SqlStatement)
867
868    Dict = {}
869    for Result in ResultSet:
870        if len(Result[0]) == 0:
871            Dict[Result[1]] = Result[2]
872
873    IncludeFileList = GetAllIncludeFiles(FullFileName)
874    for F in IncludeFileList:
875        FileID = GetTableID(F)
876        if FileID < 0:
877            continue
878
879        FileTable = 'Identifier' + str(FileID)
880        SqlStatement = """ select Modifier, Name, Value, ID
881                       from %s
882                       where Model = %d
883                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
884        ResultSet = Db.TblFile.Exec(SqlStatement)
885
886        for Result in ResultSet:
887            if not Result[2].startswith('FP ('):
888                Dict[Result[1]] = Result[2]
889            else:
890                if len(Result[0]) == 0:
891                    Dict[Result[1]] = 'VOID'
892                else:
893                    Dict[Result[1]] = GetDataTypeFromModifier(Result[0])
894
895    ComplexTypeDict[FullFileName] = Dict
896    return Dict
897
898def GetSUDict(FullFileName):
899
900    Dict = SUDict.get(FullFileName)
901    if Dict != None:
902        return Dict
903
904    FileID = GetTableID(FullFileName)
905    FileTable = 'Identifier' + str(FileID)
906    Db = GetDB()
907    SqlStatement = """ select Name, Value, ID
908                       from %s
909                       where Model = %d or Model = %d
910                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_STRUCTURE, DataClass.MODEL_IDENTIFIER_UNION)
911    ResultSet = Db.TblFile.Exec(SqlStatement)
912
913    Dict = {}
914    for Result in ResultSet:
915        if len(Result[1]) > 0:
916            Dict[Result[0]] = Result[1]
917
918    IncludeFileList = GetAllIncludeFiles(FullFileName)
919    for F in IncludeFileList:
920        FileID = GetTableID(F)
921        if FileID < 0:
922            continue
923
924        FileTable = 'Identifier' + str(FileID)
925        SqlStatement = """ select Name, Value, ID
926                       from %s
927                       where Model = %d or Model = %d
928                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_STRUCTURE, DataClass.MODEL_IDENTIFIER_UNION)
929        ResultSet = Db.TblFile.Exec(SqlStatement)
930
931        for Result in ResultSet:
932            if len(Result[1]) > 0:
933                Dict[Result[0]] = Result[1]
934
935    SUDict[FullFileName] = Dict
936    return Dict
937
938def StripComments(Str):
939    Str += '   '
940    ListFromStr = list(Str)
941
942    InComment = False
943    DoubleSlashComment = False
944    Index = 0
945    while Index < len(ListFromStr):
946        # meet new line, then no longer in a comment for //
947        if ListFromStr[Index] == '\n':
948            if InComment and DoubleSlashComment:
949                InComment = False
950                DoubleSlashComment = False
951            Index += 1
952        # check for */ comment end
953        elif InComment and not DoubleSlashComment and ListFromStr[Index] == '*' and ListFromStr[Index + 1] == '/':
954            ListFromStr[Index] = ' '
955            Index += 1
956            ListFromStr[Index] = ' '
957            Index += 1
958            InComment = False
959        # set comments to spaces
960        elif InComment:
961            ListFromStr[Index] = ' '
962            Index += 1
963        # check for // comment
964        elif ListFromStr[Index] == '/' and ListFromStr[Index + 1] == '/' and ListFromStr[Index + 2] != '\n':
965            InComment = True
966            DoubleSlashComment = True
967
968        # check for /* comment start
969        elif ListFromStr[Index] == '/' and ListFromStr[Index + 1] == '*':
970            ListFromStr[Index] = ' '
971            Index += 1
972            ListFromStr[Index] = ' '
973            Index += 1
974            InComment = True
975        else:
976            Index += 1
977
978    # restore from List to String
979    Str = "".join(ListFromStr)
980    Str = Str.rstrip(' ')
981
982    return Str
983
984def GetFinalTypeValue(Type, FieldName, TypedefDict, SUDict):
985    Value = TypedefDict.get(Type)
986    if Value == None:
987        Value = SUDict.get(Type)
988    if Value == None:
989        return None
990
991    LBPos = Value.find('{')
992    while LBPos == -1:
993        FTList = Value.split()
994        for FT in FTList:
995            if FT not in ('struct', 'union'):
996                Value = TypedefDict.get(FT)
997                if Value == None:
998                    Value = SUDict.get(FT)
999                break
1000
1001        if Value == None:
1002            return None
1003
1004        LBPos = Value.find('{')
1005
1006#    RBPos = Value.find('}')
1007    Fields = Value[LBPos + 1:]
1008    Fields = StripComments(Fields)
1009    FieldsList = Fields.split(';')
1010    for Field in FieldsList:
1011        Field = Field.strip()
1012        Index = Field.rfind(FieldName)
1013        if Index < 1:
1014            continue
1015        if not Field[Index - 1].isalnum():
1016            if Index + len(FieldName) == len(Field):
1017                Type = GetDataTypeFromModifier(Field[0:Index])
1018                return Type.strip()
1019            else:
1020            # For the condition that the field in struct is an array with [] sufixes...
1021                if not Field[Index + len(FieldName)].isalnum():
1022                    Type = GetDataTypeFromModifier(Field[0:Index])
1023                    return Type.strip()
1024
1025    return None
1026
1027def GetRealType(Type, TypedefDict, TargetType=None):
1028    if TargetType != None and Type == TargetType:
1029            return Type
1030    while TypedefDict.get(Type):
1031        Type = TypedefDict.get(Type)
1032        if TargetType != None and Type == TargetType:
1033            return Type
1034    return Type
1035
1036def GetTypeInfo(RefList, Modifier, FullFileName, TargetType=None):
1037    TypedefDict = GetTypedefDict(FullFileName)
1038    SUDict = GetSUDict(FullFileName)
1039    Type = GetDataTypeFromModifier(Modifier).replace('*', '').strip()
1040
1041    Type = Type.split()[-1]
1042    Index = 0
1043    while Index < len(RefList):
1044        FieldName = RefList[Index]
1045        FromType = GetFinalTypeValue(Type, FieldName, TypedefDict, SUDict)
1046        if FromType == None:
1047            return None
1048        # we want to determine the exact type.
1049        if TargetType != None:
1050            Type = FromType.split()[0]
1051        # we only want to check if it is a pointer
1052        else:
1053            Type = FromType
1054            if Type.find('*') != -1 and Index == len(RefList) - 1:
1055                return Type
1056            Type = FromType.split()[0]
1057
1058        Index += 1
1059
1060    Type = GetRealType(Type, TypedefDict, TargetType)
1061
1062    return Type
1063
1064def GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall=False, TargetType=None, StarList=None):
1065
1066    PredVar = PredVarList[0]
1067    FileID = GetTableID(FullFileName)
1068
1069    Db = GetDB()
1070    FileTable = 'Identifier' + str(FileID)
1071    # search variable in include files
1072
1073    # it is a function call, search function declarations and definitions
1074    if IsFuncCall:
1075        SqlStatement = """ select Modifier, ID
1076                       from %s
1077                       where Model = %d and Value = \'%s\'
1078                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, PredVar)
1079        ResultSet = Db.TblFile.Exec(SqlStatement)
1080
1081        for Result in ResultSet:
1082            Type = GetDataTypeFromModifier(Result[0]).split()[-1]
1083            TypedefDict = GetTypedefDict(FullFileName)
1084            Type = GetRealType(Type, TypedefDict, TargetType)
1085            return Type
1086
1087        IncludeFileList = GetAllIncludeFiles(FullFileName)
1088        for F in IncludeFileList:
1089            FileID = GetTableID(F)
1090            if FileID < 0:
1091                continue
1092
1093            FileTable = 'Identifier' + str(FileID)
1094            SqlStatement = """ select Modifier, ID
1095                           from %s
1096                           where Model = %d and Value = \'%s\'
1097                       """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION, PredVar)
1098            ResultSet = Db.TblFile.Exec(SqlStatement)
1099
1100            for Result in ResultSet:
1101                Type = GetDataTypeFromModifier(Result[0]).split()[-1]
1102                TypedefDict = GetTypedefDict(FullFileName)
1103                Type = GetRealType(Type, TypedefDict, TargetType)
1104                return Type
1105
1106        FileID = GetTableID(FullFileName)
1107        SqlStatement = """ select Modifier, ID
1108                       from Function
1109                       where BelongsToFile = %d and Name = \'%s\'
1110                   """ % (FileID, PredVar)
1111        ResultSet = Db.TblFile.Exec(SqlStatement)
1112
1113        for Result in ResultSet:
1114            Type = GetDataTypeFromModifier(Result[0]).split()[-1]
1115            TypedefDict = GetTypedefDict(FullFileName)
1116            Type = GetRealType(Type, TypedefDict, TargetType)
1117            return Type
1118
1119        for F in IncludeFileList:
1120            FileID = GetTableID(F)
1121            if FileID < 0:
1122                continue
1123
1124            FileTable = 'Identifier' + str(FileID)
1125            SqlStatement = """ select Modifier, ID
1126                           from Function
1127                           where BelongsToFile = %d and Name = \'%s\'
1128                       """ % (FileID, PredVar)
1129            ResultSet = Db.TblFile.Exec(SqlStatement)
1130
1131            for Result in ResultSet:
1132                Type = GetDataTypeFromModifier(Result[0]).split()[-1]
1133                TypedefDict = GetTypedefDict(FullFileName)
1134                Type = GetRealType(Type, TypedefDict, TargetType)
1135                return Type
1136
1137        return None
1138
1139    # really variable, search local variable first
1140    SqlStatement = """ select Modifier, ID
1141                       from %s
1142                       where Model = %d and Name = \'%s\' and StartLine >= %d and StartLine <= %d
1143                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, PredVar, FuncRecord[0], FuncRecord[1])
1144    ResultSet = Db.TblFile.Exec(SqlStatement)
1145    VarFound = False
1146    for Result in ResultSet:
1147        if len(PredVarList) > 1:
1148            Type = GetTypeInfo(PredVarList[1:], Result[0], FullFileName, TargetType)
1149            return Type
1150        else:
1151#            Type = GetDataTypeFromModifier(Result[0]).split()[-1]
1152            TypeList = GetDataTypeFromModifier(Result[0]).split()
1153            Type = TypeList[-1]
1154            if len(TypeList) > 1 and StarList != None:
1155                for Star in StarList:
1156                    Type = Type.strip()
1157                    Type = Type.rstrip(Star)
1158                # Get real type after de-reference pointers.
1159                if len(Type.strip()) == 0:
1160                    Type = TypeList[-2]
1161            TypedefDict = GetTypedefDict(FullFileName)
1162            Type = GetRealType(Type, TypedefDict, TargetType)
1163            return Type
1164
1165    # search function parameters second
1166    ParamList = GetParamList(FuncRecord[2])
1167    for Param in ParamList:
1168        if Param.Name.strip() == PredVar:
1169            if len(PredVarList) > 1:
1170                Type = GetTypeInfo(PredVarList[1:], Param.Modifier, FullFileName, TargetType)
1171                return Type
1172            else:
1173                TypeList = GetDataTypeFromModifier(Param.Modifier).split()
1174                Type = TypeList[-1]
1175                if Type == '*' and len(TypeList) >= 2:
1176                    Type = TypeList[-2]
1177                if len(TypeList) > 1 and StarList != None:
1178                    for Star in StarList:
1179                        Type = Type.strip()
1180                        Type = Type.rstrip(Star)
1181                    # Get real type after de-reference pointers.
1182                    if len(Type.strip()) == 0:
1183                        Type = TypeList[-2]
1184                TypedefDict = GetTypedefDict(FullFileName)
1185                Type = GetRealType(Type, TypedefDict, TargetType)
1186                return Type
1187
1188    # search global variable next
1189    SqlStatement = """ select Modifier, ID
1190           from %s
1191           where Model = %d and Name = \'%s\' and BelongsToFunction = -1
1192       """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, PredVar)
1193    ResultSet = Db.TblFile.Exec(SqlStatement)
1194
1195    for Result in ResultSet:
1196        if len(PredVarList) > 1:
1197            Type = GetTypeInfo(PredVarList[1:], Result[0], FullFileName, TargetType)
1198            return Type
1199        else:
1200            TypeList = GetDataTypeFromModifier(Result[0]).split()
1201            Type = TypeList[-1]
1202            if len(TypeList) > 1 and StarList != None:
1203                for Star in StarList:
1204                    Type = Type.strip()
1205                    Type = Type.rstrip(Star)
1206                # Get real type after de-reference pointers.
1207                if len(Type.strip()) == 0:
1208                    Type = TypeList[-2]
1209            TypedefDict = GetTypedefDict(FullFileName)
1210            Type = GetRealType(Type, TypedefDict, TargetType)
1211            return Type
1212
1213    IncludeFileList = GetAllIncludeFiles(FullFileName)
1214    for F in IncludeFileList:
1215        FileID = GetTableID(F)
1216        if FileID < 0:
1217            continue
1218
1219        FileTable = 'Identifier' + str(FileID)
1220        SqlStatement = """ select Modifier, ID
1221                       from %s
1222                       where Model = %d and BelongsToFunction = -1 and Name = \'%s\'
1223                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, PredVar)
1224        ResultSet = Db.TblFile.Exec(SqlStatement)
1225
1226        for Result in ResultSet:
1227            if len(PredVarList) > 1:
1228                Type = GetTypeInfo(PredVarList[1:], Result[0], FullFileName, TargetType)
1229                return Type
1230            else:
1231                TypeList = GetDataTypeFromModifier(Result[0]).split()
1232                Type = TypeList[-1]
1233                if len(TypeList) > 1 and StarList != None:
1234                    for Star in StarList:
1235                        Type = Type.strip()
1236                        Type = Type.rstrip(Star)
1237                    # Get real type after de-reference pointers.
1238                    if len(Type.strip()) == 0:
1239                        Type = TypeList[-2]
1240                TypedefDict = GetTypedefDict(FullFileName)
1241                Type = GetRealType(Type, TypedefDict, TargetType)
1242                return Type
1243
1244def GetTypeFromArray(Type, Var):
1245    Count = Var.count('[')
1246
1247    while Count > 0:
1248        Type = Type.strip()
1249        Type = Type.rstrip('*')
1250        Count = Count - 1
1251
1252    return Type
1253
1254def CheckFuncLayoutReturnType(FullFileName):
1255    ErrorMsgList = []
1256
1257    FileID = GetTableID(FullFileName, ErrorMsgList)
1258    if FileID < 0:
1259        return ErrorMsgList
1260
1261    Db = GetDB()
1262    FileTable = 'Identifier' + str(FileID)
1263    SqlStatement = """ select Modifier, ID, StartLine, StartColumn, EndLine, Value
1264                       from %s
1265                       where Model = %d
1266                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1267    ResultSet = Db.TblFile.Exec(SqlStatement)
1268    for Result in ResultSet:
1269        ReturnType = GetDataTypeFromModifier(Result[0])
1270        TypeStart = ReturnType.split()[0]
1271        FuncName = Result[5]
1272        if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, FuncName):
1273            continue
1274        Result0 = Result[0]
1275        if Result0.upper().startswith('STATIC'):
1276            Result0 = Result0[6:].strip()
1277        Index = Result0.find(TypeStart)
1278        if Index != 0 or Result[3] != 0:
1279            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear at the start of line' % FuncName, FileTable, Result[1])
1280
1281        if Result[2] == Result[4]:
1282            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear on its own line' % FuncName, FileTable, Result[1])
1283
1284    SqlStatement = """ select Modifier, ID, StartLine, StartColumn, FunNameStartLine, Name
1285                       from Function
1286                       where BelongsToFile = %d
1287                   """ % (FileID)
1288    ResultSet = Db.TblFile.Exec(SqlStatement)
1289    for Result in ResultSet:
1290        ReturnType = GetDataTypeFromModifier(Result[0])
1291        TypeStart = ReturnType.split()[0]
1292        FuncName = Result[5]
1293        if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, FuncName):
1294            continue
1295        Result0 = Result[0]
1296        if Result0.upper().startswith('STATIC'):
1297            Result0 = Result0[6:].strip()
1298        Index = Result0.find(ReturnType)
1299        if Index != 0 or Result[3] != 0:
1300            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_RETURN_TYPE, '[%s] Return Type should appear at the start of line' % FuncName, 'Function', Result[1])
1301
1302def CheckFuncLayoutModifier(FullFileName):
1303    ErrorMsgList = []
1304
1305    FileID = GetTableID(FullFileName, ErrorMsgList)
1306    if FileID < 0:
1307        return ErrorMsgList
1308
1309    Db = GetDB()
1310    FileTable = 'Identifier' + str(FileID)
1311    SqlStatement = """ select Modifier, ID
1312                       from %s
1313                       where Model = %d
1314                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1315    ResultSet = Db.TblFile.Exec(SqlStatement)
1316    for Result in ResultSet:
1317        ReturnType = GetDataTypeFromModifier(Result[0])
1318        TypeStart = ReturnType.split()[0]
1319        Result0 = Result[0]
1320        if Result0.upper().startswith('STATIC'):
1321            Result0 = Result0[6:].strip()
1322        Index = Result0.find(TypeStart)
1323        if Index != 0:
1324            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_OPTIONAL_FUNCTIONAL_MODIFIER, '', FileTable, Result[1])
1325
1326    SqlStatement = """ select Modifier, ID
1327                       from Function
1328                       where BelongsToFile = %d
1329                   """ % (FileID)
1330    ResultSet = Db.TblFile.Exec(SqlStatement)
1331    for Result in ResultSet:
1332        ReturnType = GetDataTypeFromModifier(Result[0])
1333        TypeStart = ReturnType.split()[0]
1334        Result0 = Result[0]
1335        if Result0.upper().startswith('STATIC'):
1336            Result0 = Result0[6:].strip()
1337        Index = Result0.find(TypeStart)
1338        if Index != 0:
1339            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_OPTIONAL_FUNCTIONAL_MODIFIER, '', 'Function', Result[1])
1340
1341def CheckFuncLayoutName(FullFileName):
1342    ErrorMsgList = []
1343    # Parameter variable format pattern.
1344    Pattern = re.compile(r'^[A-Z]+\S*[a-z]\S*$')
1345    ParamIgnoreList = ('VOID', '...')
1346    FileID = GetTableID(FullFileName, ErrorMsgList)
1347    if FileID < 0:
1348        return ErrorMsgList
1349
1350    Db = GetDB()
1351    FileTable = 'Identifier' + str(FileID)
1352    SqlStatement = """ select Name, ID, EndColumn, Value
1353                       from %s
1354                       where Model = %d
1355                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1356    ResultSet = Db.TblFile.Exec(SqlStatement)
1357    for Result in ResultSet:
1358        FuncName = Result[3]
1359        if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, FuncName):
1360            continue
1361        if Result[2] != 0:
1362            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Function name [%s] should appear at the start of a line' % FuncName, FileTable, Result[1])
1363        ParamList = GetParamList(Result[0])
1364        if len(ParamList) == 0:
1365            continue
1366        StartLine = 0
1367        for Param in ParamList:
1368            if Param.StartLine <= StartLine:
1369                PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Parameter %s should be in its own line.' % Param.Name, FileTable, Result[1])
1370            if Param.StartLine - StartLine > 1:
1371                PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Empty line appears before Parameter %s.' % Param.Name, FileTable, Result[1])
1372            if not Pattern.match(Param.Name) and not Param.Name in ParamIgnoreList and not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Param.Name):
1373                PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Parameter [%s] NOT follow naming convention.' % Param.Name, FileTable, Result[1])
1374            StartLine = Param.StartLine
1375
1376        if not Result[0].endswith('\n  )') and not Result[0].endswith('\r  )'):
1377            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, '\')\' should be on a new line and indented two spaces', FileTable, Result[1])
1378
1379    SqlStatement = """ select Modifier, ID, FunNameStartColumn, Name
1380                       from Function
1381                       where BelongsToFile = %d
1382                   """ % (FileID)
1383    ResultSet = Db.TblFile.Exec(SqlStatement)
1384    for Result in ResultSet:
1385        FuncName = Result[3]
1386        if EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, FuncName):
1387            continue
1388        if Result[2] != 0:
1389            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Function name [%s] should appear at the start of a line' % FuncName, 'Function', Result[1])
1390        ParamList = GetParamList(Result[0])
1391        if len(ParamList) == 0:
1392            continue
1393        StartLine = 0
1394        for Param in ParamList:
1395            if Param.StartLine <= StartLine:
1396                PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Parameter %s should be in its own line.' % Param.Name, 'Function', Result[1])
1397            if Param.StartLine - StartLine > 1:
1398                PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, 'Empty line appears before Parameter %s.' % Param.Name, 'Function', Result[1])
1399            if not Pattern.match(Param.Name) and not Param.Name in ParamIgnoreList and not EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Param.Name):
1400                PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Parameter [%s] NOT follow naming convention.' % Param.Name, FileTable, Result[1])
1401            StartLine = Param.StartLine
1402        if not Result[0].endswith('\n  )') and not Result[0].endswith('\r  )'):
1403            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_NAME, '\')\' should be on a new line and indented two spaces', 'Function', Result[1])
1404
1405def CheckFuncLayoutPrototype(FullFileName):
1406    ErrorMsgList = []
1407
1408    FileID = GetTableID(FullFileName, ErrorMsgList)
1409    if FileID < 0:
1410        return ErrorMsgList
1411
1412    FileTable = 'Identifier' + str(FileID)
1413    Db = GetDB()
1414    SqlStatement = """ select Modifier, Header, Name, ID
1415                       from Function
1416                       where BelongsToFile = %d
1417                   """ % (FileID)
1418    ResultSet = Db.TblFile.Exec(SqlStatement)
1419    if len(ResultSet) == 0:
1420        return ErrorMsgList
1421
1422    FuncDefList = []
1423    for Result in ResultSet:
1424        FuncDefList.append(Result)
1425
1426    SqlStatement = """ select Modifier, Name, ID
1427                       from %s
1428                       where Model = %d
1429                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1430    ResultSet = Db.TblFile.Exec(SqlStatement)
1431    FuncDeclList = []
1432    for Result in ResultSet:
1433        FuncDeclList.append(Result)
1434
1435    UndeclFuncList = []
1436    for FuncDef in FuncDefList:
1437        FuncName = FuncDef[2].strip()
1438        FuncModifier = FuncDef[0]
1439        FuncDefHeader = FuncDef[1]
1440        for FuncDecl in FuncDeclList:
1441            LBPos = FuncDecl[1].find('(')
1442            DeclName = FuncDecl[1][0:LBPos].strip()
1443            DeclModifier = FuncDecl[0]
1444            if DeclName == FuncName:
1445                if DiffModifier(FuncModifier, DeclModifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, FuncName):
1446                    PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, 'Function [%s] modifier different with prototype.' % FuncName, 'Function', FuncDef[3])
1447                ParamListOfDef = GetParamList(FuncDefHeader)
1448                ParamListOfDecl = GetParamList(FuncDecl[1])
1449                if len(ParamListOfDef) != len(ParamListOfDecl) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, FuncName):
1450                    PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, 'Parameter number different in function [%s].' % FuncName, 'Function', FuncDef[3])
1451                    break
1452
1453                Index = 0
1454                while Index < len(ParamListOfDef):
1455                    if DiffModifier(ParamListOfDef[Index].Modifier, ParamListOfDecl[Index].Modifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, FuncName):
1456                        PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, 'Parameter %s has different modifier with prototype in function [%s].' % (ParamListOfDef[Index].Name, FuncName), 'Function', FuncDef[3])
1457                    Index += 1
1458                break
1459        else:
1460            UndeclFuncList.append(FuncDef)
1461
1462    IncludeFileList = GetAllIncludeFiles(FullFileName)
1463    FuncDeclList = []
1464    for F in IncludeFileList:
1465        FileID = GetTableID(F, ErrorMsgList)
1466        if FileID < 0:
1467            continue
1468
1469        FileTable = 'Identifier' + str(FileID)
1470        SqlStatement = """ select Modifier, Name, ID
1471                       from %s
1472                       where Model = %d
1473                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1474        ResultSet = Db.TblFile.Exec(SqlStatement)
1475
1476        for Result in ResultSet:
1477            FuncDeclList.append(Result)
1478
1479    for FuncDef in UndeclFuncList:
1480        FuncName = FuncDef[2].strip()
1481        FuncModifier = FuncDef[0]
1482        FuncDefHeader = FuncDef[1]
1483        for FuncDecl in FuncDeclList:
1484            LBPos = FuncDecl[1].find('(')
1485            DeclName = FuncDecl[1][0:LBPos].strip()
1486            DeclModifier = FuncDecl[0]
1487            if DeclName == FuncName:
1488                if DiffModifier(FuncModifier, DeclModifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, FuncName):
1489                    PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE, 'Function [%s] modifier different with prototype.' % FuncName, 'Function', FuncDef[3])
1490                ParamListOfDef = GetParamList(FuncDefHeader)
1491                ParamListOfDecl = GetParamList(FuncDecl[1])
1492                if len(ParamListOfDef) != len(ParamListOfDecl) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, FuncName):
1493                    PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_2, 'Parameter number different in function [%s].' % FuncName, 'Function', FuncDef[3])
1494                    break
1495
1496                Index = 0
1497                while Index < len(ParamListOfDef):
1498                    if DiffModifier(ParamListOfDef[Index].Modifier, ParamListOfDecl[Index].Modifier) and not EccGlobalData.gException.IsException(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, FuncName):
1499                        PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_PROTO_TYPE_3, 'Parameter %s has different modifier with prototype in function [%s].' % (ParamListOfDef[Index].Name, FuncName), 'Function', FuncDef[3])
1500                    Index += 1
1501                break
1502
1503def CheckFuncLayoutBody(FullFileName):
1504    ErrorMsgList = []
1505
1506    FileID = GetTableID(FullFileName, ErrorMsgList)
1507    if FileID < 0:
1508        return ErrorMsgList
1509
1510    FileTable = 'Identifier' + str(FileID)
1511    Db = GetDB()
1512    SqlStatement = """ select BodyStartColumn, EndColumn, ID
1513                       from Function
1514                       where BelongsToFile = %d
1515                   """ % (FileID)
1516    ResultSet = Db.TblFile.Exec(SqlStatement)
1517    if len(ResultSet) == 0:
1518        return ErrorMsgList
1519    for Result in ResultSet:
1520        if Result[0] != 0:
1521            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY, 'open brace should be at the very beginning of a line.', 'Function', Result[2])
1522        if Result[1] != 0:
1523            PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_FUNCTION_BODY, 'close brace should be at the very beginning of a line.', 'Function', Result[2])
1524
1525def CheckFuncLayoutLocalVariable(FullFileName):
1526    ErrorMsgList = []
1527
1528    FileID = GetTableID(FullFileName, ErrorMsgList)
1529    if FileID < 0:
1530        return ErrorMsgList
1531
1532    Db = GetDB()
1533    FileTable = 'Identifier' + str(FileID)
1534    SqlStatement = """ select ID
1535                       from Function
1536                       where BelongsToFile = %d
1537                   """ % (FileID)
1538    ResultSet = Db.TblFile.Exec(SqlStatement)
1539    if len(ResultSet) == 0:
1540        return ErrorMsgList
1541    FL = []
1542    for Result in ResultSet:
1543        FL.append(Result)
1544
1545    for F in FL:
1546        SqlStatement = """ select Name, Value, ID, Modifier
1547                       from %s
1548                       where Model = %d and BelongsToFunction = %d
1549                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE, F[0])
1550        ResultSet = Db.TblFile.Exec(SqlStatement)
1551        if len(ResultSet) == 0:
1552            continue
1553
1554        for Result in ResultSet:
1555            if len(Result[1]) > 0 and 'CONST' not in Result[3]:
1556                PrintErrorMsg(ERROR_C_FUNCTION_LAYOUT_CHECK_NO_INIT_OF_VARIABLE, 'Variable Name: %s' % Result[0], FileTable, Result[2])
1557
1558def CheckMemberVariableFormat(Name, Value, FileTable, TdId, ModelId):
1559    ErrMsgList = []
1560    # Member variable format pattern.
1561    Pattern = re.compile(r'^[A-Z]+\S*[a-z]\S*$')
1562
1563    LBPos = Value.find('{')
1564    RBPos = Value.rfind('}')
1565    if LBPos == -1 or RBPos == -1:
1566        return ErrMsgList
1567
1568    Fields = Value[LBPos + 1 : RBPos]
1569    Fields = StripComments(Fields).strip()
1570    NestPos = Fields.find ('struct')
1571    if NestPos != -1 and (NestPos + len('struct') < len(Fields)):
1572        if not Fields[NestPos + len('struct') + 1].isalnum():
1573            if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, Name):
1574                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, 'Nested struct in [%s].' % (Name), FileTable, TdId)
1575            return ErrMsgList
1576    NestPos = Fields.find ('union')
1577    if NestPos != -1 and (NestPos + len('union') < len(Fields)):
1578        if not Fields[NestPos + len('union') + 1].isalnum():
1579            if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, Name):
1580                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, 'Nested union in [%s].' % (Name), FileTable, TdId)
1581            return ErrMsgList
1582    NestPos = Fields.find ('enum')
1583    if NestPos != -1 and (NestPos + len('enum') < len(Fields)):
1584        if not Fields[NestPos + len('enum') + 1].isalnum():
1585            if not EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, Name):
1586                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NESTED_STRUCTURE, 'Nested enum in [%s].' % (Name), FileTable, TdId)
1587            return ErrMsgList
1588
1589    if ModelId == DataClass.MODEL_IDENTIFIER_ENUMERATE:
1590        FieldsList = Fields.split(',')
1591        # deal with enum is pre-assigned a value by function call ( , , , ...)
1592        QuoteCount = 0
1593        Index = 0
1594        RemoveCurrentElement = False
1595        while Index < len(FieldsList):
1596            Field = FieldsList[Index]
1597
1598            if Field.find('(') != -1:
1599                QuoteCount += 1
1600                RemoveCurrentElement = True
1601                Index += 1
1602                continue
1603
1604            if Field.find(')') != -1 and QuoteCount > 0:
1605                QuoteCount -= 1
1606
1607            if RemoveCurrentElement:
1608                FieldsList.remove(Field)
1609                if QuoteCount == 0:
1610                    RemoveCurrentElement = False
1611                continue
1612
1613            if QuoteCount == 0:
1614                RemoveCurrentElement = False
1615
1616            Index += 1
1617    else:
1618        FieldsList = Fields.split(';')
1619
1620    for Field in FieldsList:
1621        Field = Field.strip()
1622        if Field == '':
1623            continue
1624        # For the condition that the field in struct is an array with [] sufixes...
1625        if Field[-1] == ']':
1626            LBPos = Field.find('[')
1627            Field = Field[0:LBPos]
1628        # For the condition that bit field ": Number"
1629        if Field.find(':') != -1:
1630            ColonPos = Field.find(':')
1631            Field = Field[0:ColonPos]
1632
1633        Field = Field.strip()
1634        if Field == '':
1635            continue
1636        if Field.startswith("#"):
1637            continue
1638        # Enum could directly assign value to variable
1639        Field = Field.split('=')[0].strip()
1640        TokenList = Field.split()
1641        # Remove pointers before variable
1642        Token = TokenList[-1]
1643        if Token in ['OPTIONAL']:
1644            Token = TokenList[-2]
1645        if not Pattern.match(Token.lstrip('*')):
1646            ErrMsgList.append(Token.lstrip('*'))
1647
1648    return ErrMsgList
1649
1650def CheckDeclTypedefFormat(FullFileName, ModelId):
1651    ErrorMsgList = []
1652
1653    FileID = GetTableID(FullFileName, ErrorMsgList)
1654    if FileID < 0:
1655        return ErrorMsgList
1656
1657    Db = GetDB()
1658    FileTable = 'Identifier' + str(FileID)
1659    SqlStatement = """ select Name, StartLine, EndLine, ID, Value
1660                       from %s
1661                       where Model = %d
1662                   """ % (FileTable, ModelId)
1663    ResultSet = Db.TblFile.Exec(SqlStatement)
1664    ResultList = []
1665    for Result in ResultSet:
1666        ResultList.append(Result)
1667
1668    ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_ALL
1669    if ModelId == DataClass.MODEL_IDENTIFIER_STRUCTURE:
1670        ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_STRUCTURE_DECLARATION
1671    elif ModelId == DataClass.MODEL_IDENTIFIER_ENUMERATE:
1672        ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_ENUMERATED_TYPE
1673    elif ModelId == DataClass.MODEL_IDENTIFIER_UNION:
1674        ErrorType = ERROR_DECLARATION_DATA_TYPE_CHECK_UNION_TYPE
1675
1676    SqlStatement = """ select Modifier, Name, Value, StartLine, EndLine, ID
1677                       from %s
1678                       where Model = %d
1679                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
1680    TdSet = Db.TblFile.Exec(SqlStatement)
1681    TdList = []
1682    for Td in TdSet:
1683        TdList.append(Td)
1684    # Check member variable name format that from typedefs of ONLY this file.
1685    for Td in TdList:
1686        Name = Td[1].strip()
1687        Value = Td[2].strip()
1688        if Value.startswith('enum'):
1689            ValueModelId = DataClass.MODEL_IDENTIFIER_ENUMERATE
1690        elif Value.startswith('struct'):
1691            ValueModelId = DataClass.MODEL_IDENTIFIER_STRUCTURE
1692        elif Value.startswith('union'):
1693            ValueModelId = DataClass.MODEL_IDENTIFIER_UNION
1694        else:
1695            continue
1696
1697        if ValueModelId != ModelId:
1698            continue
1699        # Check member variable format.
1700        ErrMsgList = CheckMemberVariableFormat(Name, Value, FileTable, Td[5], ModelId)
1701        for ErrMsg in ErrMsgList:
1702            if EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Name + '.' + ErrMsg):
1703                continue
1704            PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Member variable [%s] NOT follow naming convention.' % (Name + '.' + ErrMsg), FileTable, Td[5])
1705
1706    # First check in current file to see whether struct/union/enum is typedef-ed.
1707    UntypedefedList = []
1708    for Result in ResultList:
1709        # Check member variable format.
1710        Name = Result[0].strip()
1711        Value = Result[4].strip()
1712        if Value.startswith('enum'):
1713            ValueModelId = DataClass.MODEL_IDENTIFIER_ENUMERATE
1714        elif Value.startswith('struct'):
1715            ValueModelId = DataClass.MODEL_IDENTIFIER_STRUCTURE
1716        elif Value.startswith('union'):
1717            ValueModelId = DataClass.MODEL_IDENTIFIER_UNION
1718        else:
1719            continue
1720
1721        if ValueModelId != ModelId:
1722            continue
1723        ErrMsgList = CheckMemberVariableFormat(Name, Value, FileTable, Result[3], ModelId)
1724        for ErrMsg in ErrMsgList:
1725            if EccGlobalData.gException.IsException(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, Result[0] + '.' + ErrMsg):
1726                continue
1727            PrintErrorMsg(ERROR_NAMING_CONVENTION_CHECK_VARIABLE_NAME, 'Member variable [%s] NOT follow naming convention.' % (Result[0] + '.' + ErrMsg), FileTable, Result[3])
1728        # Check whether it is typedefed.
1729        Found = False
1730        for Td in TdList:
1731            # skip function pointer
1732            if len(Td[0]) > 0:
1733                continue
1734            if Result[1] >= Td[3] and Td[4] >= Result[2]:
1735                Found = True
1736                if not Td[1].isupper():
1737                    PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
1738            if Result[0] in Td[2].split():
1739                Found = True
1740                if not Td[1].isupper():
1741                    PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
1742            if Found:
1743                break
1744
1745        if not Found:
1746            UntypedefedList.append(Result)
1747            continue
1748
1749    if len(UntypedefedList) == 0:
1750        return
1751
1752    IncludeFileList = GetAllIncludeFiles(FullFileName)
1753    TdList = []
1754    for F in IncludeFileList:
1755        FileID = GetTableID(F, ErrorMsgList)
1756        if FileID < 0:
1757            continue
1758
1759        IncludeFileTable = 'Identifier' + str(FileID)
1760        SqlStatement = """ select Modifier, Name, Value, StartLine, EndLine, ID
1761                       from %s
1762                       where Model = %d
1763                   """ % (IncludeFileTable, DataClass.MODEL_IDENTIFIER_TYPEDEF)
1764        ResultSet = Db.TblFile.Exec(SqlStatement)
1765        TdList.extend(ResultSet)
1766
1767    for Result in UntypedefedList:
1768
1769        # Check whether it is typedefed.
1770        Found = False
1771        for Td in TdList:
1772
1773            if len(Td[0]) > 0:
1774                continue
1775            if Result[1] >= Td[3] and Td[4] >= Result[2]:
1776                Found = True
1777                if not Td[1].isupper():
1778                    PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
1779            if Result[0] in Td[2].split():
1780                Found = True
1781                if not Td[1].isupper():
1782                    PrintErrorMsg(ErrorType, 'Typedef should be UPPER case', FileTable, Td[5])
1783            if Found:
1784                break
1785
1786        if not Found:
1787            PrintErrorMsg(ErrorType, 'No Typedef for %s' % Result[0], FileTable, Result[3])
1788            continue
1789
1790def CheckDeclStructTypedef(FullFileName):
1791    CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_STRUCTURE)
1792
1793def CheckDeclEnumTypedef(FullFileName):
1794    CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_ENUMERATE)
1795
1796def CheckDeclUnionTypedef(FullFileName):
1797    CheckDeclTypedefFormat(FullFileName, DataClass.MODEL_IDENTIFIER_UNION)
1798
1799def CheckDeclArgModifier(FullFileName):
1800    ErrorMsgList = []
1801
1802    FileID = GetTableID(FullFileName, ErrorMsgList)
1803    if FileID < 0:
1804        return ErrorMsgList
1805
1806    Db = GetDB()
1807    FileTable = 'Identifier' + str(FileID)
1808    SqlStatement = """ select Modifier, Name, ID
1809                       from %s
1810                       where Model = %d
1811                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE)
1812    ResultSet = Db.TblFile.Exec(SqlStatement)
1813    ModifierTuple = ('IN', 'OUT', 'OPTIONAL', 'UNALIGNED')
1814    MAX_MODIFIER_LENGTH = 100
1815    for Result in ResultSet:
1816        for Modifier in ModifierTuple:
1817            if PatternInModifier(Result[0], Modifier) and len(Result[0]) < MAX_MODIFIER_LENGTH:
1818                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Variable Modifier %s' % Result[0], FileTable, Result[2])
1819                break
1820
1821    SqlStatement = """ select Modifier, Name, ID
1822                       from %s
1823                       where Model = %d
1824                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1825    ResultSet = Db.TblFile.Exec(SqlStatement)
1826    for Result in ResultSet:
1827        for Modifier in ModifierTuple:
1828            if PatternInModifier(Result[0], Modifier):
1829                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Return Type Modifier %s' % Result[0], FileTable, Result[2])
1830                break
1831
1832    SqlStatement = """ select Modifier, Header, ID
1833                       from Function
1834                       where BelongsToFile = %d
1835                   """ % (FileID)
1836    ResultSet = Db.TblFile.Exec(SqlStatement)
1837    for Result in ResultSet:
1838        for Modifier in ModifierTuple:
1839            if PatternInModifier(Result[0], Modifier):
1840                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_IN_OUT_MODIFIER, 'Return Type Modifier %s' % Result[0], FileTable, Result[2])
1841                break
1842
1843def CheckDeclNoUseCType(FullFileName):
1844    ErrorMsgList = []
1845
1846    FileID = GetTableID(FullFileName, ErrorMsgList)
1847    if FileID < 0:
1848        return ErrorMsgList
1849
1850    Db = GetDB()
1851    FileTable = 'Identifier' + str(FileID)
1852    SqlStatement = """ select Modifier, Name, ID
1853                       from %s
1854                       where Model = %d
1855                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE)
1856    ResultSet = Db.TblFile.Exec(SqlStatement)
1857    CTypeTuple = ('int', 'unsigned', 'char', 'void', 'static', 'long')
1858    for Result in ResultSet:
1859        for Type in CTypeTuple:
1860            if PatternInModifier(Result[0], Type):
1861                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, 'Variable type %s' % Type, FileTable, Result[2])
1862                break
1863
1864    SqlStatement = """ select Modifier, Name, ID, Value
1865                       from %s
1866                       where Model = %d
1867                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
1868    ResultSet = Db.TblFile.Exec(SqlStatement)
1869    for Result in ResultSet:
1870        ParamList = GetParamList(Result[1])
1871        FuncName = Result[3]
1872        if EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, FuncName):
1873            continue
1874        for Type in CTypeTuple:
1875            if PatternInModifier(Result[0], Type):
1876                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, '%s Return type %s' % (FuncName, Result[0]), FileTable, Result[2])
1877
1878            for Param in ParamList:
1879                if PatternInModifier(Param.Modifier, Type):
1880                    PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, 'Parameter %s' % Param.Name, FileTable, Result[2])
1881
1882    SqlStatement = """ select Modifier, Header, ID, Name
1883                       from Function
1884                       where BelongsToFile = %d
1885                   """ % (FileID)
1886    ResultSet = Db.TblFile.Exec(SqlStatement)
1887    for Result in ResultSet:
1888        ParamList = GetParamList(Result[1])
1889        FuncName = Result[3]
1890        if EccGlobalData.gException.IsException(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, FuncName):
1891            continue
1892        for Type in CTypeTuple:
1893            if PatternInModifier(Result[0], Type):
1894                PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, '[%s] Return type %s' % (FuncName, Result[0]), FileTable, Result[2])
1895
1896            for Param in ParamList:
1897                if PatternInModifier(Param.Modifier, Type):
1898                    PrintErrorMsg(ERROR_DECLARATION_DATA_TYPE_CHECK_NO_USE_C_TYPE, 'Parameter %s' % Param.Name, FileTable, Result[2])
1899
1900
1901def CheckPointerNullComparison(FullFileName):
1902    ErrorMsgList = []
1903
1904    FileID = GetTableID(FullFileName, ErrorMsgList)
1905    if FileID < 0:
1906        return ErrorMsgList
1907
1908    # cache the found function return type to accelerate later checking in this file.
1909    FuncReturnTypeDict = {}
1910
1911    Db = GetDB()
1912    FileTable = 'Identifier' + str(FileID)
1913    SqlStatement = """ select Value, StartLine, ID
1914                       from %s
1915                       where Model = %d
1916                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION)
1917    ResultSet = Db.TblFile.Exec(SqlStatement)
1918    if len(ResultSet) == 0:
1919        return
1920    PSL = []
1921    for Result in ResultSet:
1922        PSL.append([Result[0], Result[1], Result[2]])
1923
1924    SqlStatement = """ select BodyStartLine, EndLine, Header, Modifier, ID
1925                       from Function
1926                       where BelongsToFile = %d
1927                   """ % (FileID)
1928    ResultSet = Db.TblFile.Exec(SqlStatement)
1929    FL = []
1930    for Result in ResultSet:
1931        FL.append([Result[0], Result[1], Result[2], Result[3], Result[4]])
1932
1933    p = GetFuncDeclPattern()
1934    for Str in PSL:
1935        FuncRecord = GetFuncContainsPE(Str[1], FL)
1936        if FuncRecord == None:
1937            continue
1938
1939        for Exp in GetPredicateListFromPredicateExpStr(Str[0]):
1940            PredInfo = SplitPredicateStr(Exp)
1941            if PredInfo[1] == None:
1942                PredVarStr = PredInfo[0][0].strip()
1943                IsFuncCall = False
1944                SearchInCache = False
1945                # PredVarStr may contain '.' or '->'
1946                TmpStr = PredVarStr.replace('.', '').replace('->', '')
1947                if p.match(TmpStr):
1948                    PredVarStr = PredVarStr[0:PredVarStr.find('(')]
1949                    SearchInCache = True
1950                    # Only direct function call using IsFuncCall branch. Multi-level ref. function call is considered a variable.
1951                    if TmpStr.startswith(PredVarStr):
1952                        IsFuncCall = True
1953
1954                if PredVarStr.strip() in IgnoredKeywordList:
1955                    continue
1956                StarList = []
1957                PredVarList = GetCNameList(PredVarStr, StarList)
1958                # No variable found, maybe value first? like (0 == VarName)
1959                if len(PredVarList) == 0:
1960                    continue
1961                if SearchInCache:
1962                    Type = FuncReturnTypeDict.get(PredVarStr)
1963                    if Type != None:
1964                        if Type.find('*') != -1 and Type != 'BOOLEAN*':
1965                            PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_COMPARISON_NULL_TYPE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
1966                        continue
1967
1968                    if PredVarStr in FuncReturnTypeDict:
1969                        continue
1970
1971                Type = GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall, None, StarList)
1972                if SearchInCache:
1973                    FuncReturnTypeDict[PredVarStr] = Type
1974                if Type == None:
1975                    continue
1976                Type = GetTypeFromArray(Type, PredVarStr)
1977                if Type.find('*') != -1 and Type != 'BOOLEAN*':
1978                    PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_COMPARISON_NULL_TYPE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
1979
1980def CheckNonBooleanValueComparison(FullFileName):
1981    ErrorMsgList = []
1982
1983    FileID = GetTableID(FullFileName, ErrorMsgList)
1984    if FileID < 0:
1985        return ErrorMsgList
1986
1987    # cache the found function return type to accelerate later checking in this file.
1988    FuncReturnTypeDict = {}
1989
1990    Db = GetDB()
1991    FileTable = 'Identifier' + str(FileID)
1992    SqlStatement = """ select Value, StartLine, ID
1993                       from %s
1994                       where Model = %d
1995                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION)
1996    ResultSet = Db.TblFile.Exec(SqlStatement)
1997    if len(ResultSet) == 0:
1998        return
1999    PSL = []
2000    for Result in ResultSet:
2001        PSL.append([Result[0], Result[1], Result[2]])
2002
2003    SqlStatement = """ select BodyStartLine, EndLine, Header, Modifier, ID
2004                       from Function
2005                       where BelongsToFile = %d
2006                   """ % (FileID)
2007    ResultSet = Db.TblFile.Exec(SqlStatement)
2008    FL = []
2009    for Result in ResultSet:
2010        FL.append([Result[0], Result[1], Result[2], Result[3], Result[4]])
2011
2012    p = GetFuncDeclPattern()
2013    for Str in PSL:
2014        FuncRecord = GetFuncContainsPE(Str[1], FL)
2015        if FuncRecord == None:
2016            continue
2017
2018        for Exp in GetPredicateListFromPredicateExpStr(Str[0]):
2019            PredInfo = SplitPredicateStr(Exp)
2020            if PredInfo[1] == None:
2021                PredVarStr = PredInfo[0][0].strip()
2022                IsFuncCall = False
2023                SearchInCache = False
2024                # PredVarStr may contain '.' or '->'
2025                TmpStr = PredVarStr.replace('.', '').replace('->', '')
2026                if p.match(TmpStr):
2027                    PredVarStr = PredVarStr[0:PredVarStr.find('(')]
2028                    SearchInCache = True
2029                    # Only direct function call using IsFuncCall branch. Multi-level ref. function call is considered a variable.
2030                    if TmpStr.startswith(PredVarStr):
2031                        IsFuncCall = True
2032
2033                if PredVarStr.strip() in IgnoredKeywordList:
2034                    continue
2035                StarList = []
2036                PredVarList = GetCNameList(PredVarStr, StarList)
2037                # No variable found, maybe value first? like (0 == VarName)
2038                if len(PredVarList) == 0:
2039                    continue
2040
2041                if SearchInCache:
2042                    Type = FuncReturnTypeDict.get(PredVarStr)
2043                    if Type != None:
2044                        if Type.find('BOOLEAN') == -1:
2045                            PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_NO_BOOLEAN_OPERATOR, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
2046                        continue
2047
2048                    if PredVarStr in FuncReturnTypeDict:
2049                        continue
2050                Type = GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall, 'BOOLEAN', StarList)
2051                if SearchInCache:
2052                    FuncReturnTypeDict[PredVarStr] = Type
2053                if Type == None:
2054                    continue
2055                if Type.find('BOOLEAN') == -1:
2056                    PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_NO_BOOLEAN_OPERATOR, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
2057
2058
2059def CheckBooleanValueComparison(FullFileName):
2060    ErrorMsgList = []
2061
2062    FileID = GetTableID(FullFileName, ErrorMsgList)
2063    if FileID < 0:
2064        return ErrorMsgList
2065
2066    # cache the found function return type to accelerate later checking in this file.
2067    FuncReturnTypeDict = {}
2068
2069    Db = GetDB()
2070    FileTable = 'Identifier' + str(FileID)
2071    SqlStatement = """ select Value, StartLine, ID
2072                       from %s
2073                       where Model = %d
2074                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_PREDICATE_EXPRESSION)
2075    ResultSet = Db.TblFile.Exec(SqlStatement)
2076    if len(ResultSet) == 0:
2077        return
2078    PSL = []
2079    for Result in ResultSet:
2080        PSL.append([Result[0], Result[1], Result[2]])
2081
2082    SqlStatement = """ select BodyStartLine, EndLine, Header, Modifier, ID
2083                       from Function
2084                       where BelongsToFile = %d
2085                   """ % (FileID)
2086    ResultSet = Db.TblFile.Exec(SqlStatement)
2087    FL = []
2088    for Result in ResultSet:
2089        FL.append([Result[0], Result[1], Result[2], Result[3], Result[4]])
2090
2091    p = GetFuncDeclPattern()
2092    for Str in PSL:
2093        FuncRecord = GetFuncContainsPE(Str[1], FL)
2094        if FuncRecord == None:
2095            continue
2096
2097        for Exp in GetPredicateListFromPredicateExpStr(Str[0]):
2098            PredInfo = SplitPredicateStr(Exp)
2099            if PredInfo[1] in ('==', '!=') and PredInfo[0][1] in ('TRUE', 'FALSE'):
2100                PredVarStr = PredInfo[0][0].strip()
2101                IsFuncCall = False
2102                SearchInCache = False
2103                # PredVarStr may contain '.' or '->'
2104                TmpStr = PredVarStr.replace('.', '').replace('->', '')
2105                if p.match(TmpStr):
2106                    PredVarStr = PredVarStr[0:PredVarStr.find('(')]
2107                    SearchInCache = True
2108                    # Only direct function call using IsFuncCall branch. Multi-level ref. function call is considered a variable.
2109                    if TmpStr.startswith(PredVarStr):
2110                        IsFuncCall = True
2111
2112                if PredVarStr.strip() in IgnoredKeywordList:
2113                    continue
2114                StarList = []
2115                PredVarList = GetCNameList(PredVarStr, StarList)
2116                # No variable found, maybe value first? like (0 == VarName)
2117                if len(PredVarList) == 0:
2118                    continue
2119
2120                if SearchInCache:
2121                    Type = FuncReturnTypeDict.get(PredVarStr)
2122                    if Type != None:
2123                        if Type.find('BOOLEAN') != -1:
2124                            PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_BOOLEAN_VALUE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
2125                        continue
2126
2127                    if PredVarStr in FuncReturnTypeDict:
2128                        continue
2129
2130                Type = GetVarInfo(PredVarList, FuncRecord, FullFileName, IsFuncCall, 'BOOLEAN', StarList)
2131                if SearchInCache:
2132                    FuncReturnTypeDict[PredVarStr] = Type
2133                if Type == None:
2134                    continue
2135                if Type.find('BOOLEAN') != -1:
2136                    PrintErrorMsg(ERROR_PREDICATE_EXPRESSION_CHECK_BOOLEAN_VALUE, 'Predicate Expression: %s' % Exp, FileTable, Str[2])
2137
2138
2139def CheckHeaderFileData(FullFileName):
2140    ErrorMsgList = []
2141
2142    FileID = GetTableID(FullFileName, ErrorMsgList)
2143    if FileID < 0:
2144        return ErrorMsgList
2145
2146    Db = GetDB()
2147    FileTable = 'Identifier' + str(FileID)
2148    SqlStatement = """ select ID, Modifier
2149                       from %s
2150                       where Model = %d
2151                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_VARIABLE)
2152    ResultSet = Db.TblFile.Exec(SqlStatement)
2153    for Result in ResultSet:
2154        if not Result[1].startswith('extern'):
2155            PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_DATA, 'Variable definition appears in header file', FileTable, Result[0])
2156
2157    SqlStatement = """ select ID
2158                       from Function
2159                       where BelongsToFile = %d
2160                   """ % FileID
2161    ResultSet = Db.TblFile.Exec(SqlStatement)
2162    for Result in ResultSet:
2163        PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_DATA, 'Function definition appears in header file', 'Function', Result[0])
2164
2165    return ErrorMsgList
2166
2167def CheckHeaderFileIfndef(FullFileName):
2168    ErrorMsgList = []
2169
2170    FileID = GetTableID(FullFileName, ErrorMsgList)
2171    if FileID < 0:
2172        return ErrorMsgList
2173
2174    Db = GetDB()
2175    FileTable = 'Identifier' + str(FileID)
2176    SqlStatement = """ select Value, StartLine
2177                       from %s
2178                       where Model = %d order by StartLine
2179                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_MACRO_IFNDEF)
2180    ResultSet = Db.TblFile.Exec(SqlStatement)
2181    if len(ResultSet) == 0:
2182        PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_1, '', 'File', FileID)
2183        return ErrorMsgList
2184    for Result in ResultSet:
2185        SqlStatement = """ select Value, EndLine
2186                       from %s
2187                       where EndLine < %d
2188                   """ % (FileTable, Result[1])
2189        ResultSet = Db.TblFile.Exec(SqlStatement)
2190        for Result in ResultSet:
2191            if not Result[0].startswith('/*') and not Result[0].startswith('//'):
2192                PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_2, '', 'File', FileID)
2193        break
2194
2195    SqlStatement = """ select Value
2196                       from %s
2197                       where StartLine > (select max(EndLine) from %s where Model = %d)
2198                   """ % (FileTable, FileTable, DataClass.MODEL_IDENTIFIER_MACRO_ENDIF)
2199    ResultSet = Db.TblFile.Exec(SqlStatement)
2200    for Result in ResultSet:
2201        if not Result[0].startswith('/*') and not Result[0].startswith('//'):
2202            PrintErrorMsg(ERROR_INCLUDE_FILE_CHECK_IFNDEF_STATEMENT_3, '', 'File', FileID)
2203    return ErrorMsgList
2204
2205def CheckDoxygenCommand(FullFileName):
2206    ErrorMsgList = []
2207
2208    FileID = GetTableID(FullFileName, ErrorMsgList)
2209    if FileID < 0:
2210        return ErrorMsgList
2211
2212    Db = GetDB()
2213    FileTable = 'Identifier' + str(FileID)
2214    SqlStatement = """ select Value, ID
2215                       from %s
2216                       where Model = %d or Model = %d
2217                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT, DataClass.MODEL_IDENTIFIER_FUNCTION_HEADER)
2218    ResultSet = Db.TblFile.Exec(SqlStatement)
2219    DoxygenCommandList = ['bug', 'todo', 'example', 'file', 'attention', 'param', 'post', 'pre', 'retval', 'return', 'sa', 'since', 'test', 'note', 'par']
2220    for Result in ResultSet:
2221        CommentStr = Result[0]
2222        CommentPartList = CommentStr.split()
2223        for Part in CommentPartList:
2224            if Part.upper() == 'BUGBUG':
2225                PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Bug should be marked with doxygen tag @bug', FileTable, Result[1])
2226            if Part.upper() == 'TODO':
2227                PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'ToDo should be marked with doxygen tag @todo', FileTable, Result[1])
2228            if Part.startswith('@'):
2229                if EccGlobalData.gException.IsException(ERROR_DOXYGEN_CHECK_COMMAND, Part):
2230                    continue
2231                if Part.lstrip('@').isalpha():
2232                    if Part.lstrip('@') not in DoxygenCommandList:
2233                        PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1])
2234                else:
2235                    Index = Part.find('[')
2236                    if Index == -1:
2237                        PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1])
2238                    RealCmd = Part[1:Index]
2239                    if RealCmd not in DoxygenCommandList:
2240                        PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMAND, 'Unknown doxygen command %s' % Part, FileTable, Result[1])
2241
2242
2243def CheckDoxygenTripleForwardSlash(FullFileName):
2244    ErrorMsgList = []
2245
2246    FileID = GetTableID(FullFileName, ErrorMsgList)
2247    if FileID < 0:
2248        return ErrorMsgList
2249
2250    Db = GetDB()
2251
2252    SqlStatement = """ select ID, BodyStartLine, BodyStartColumn, EndLine, EndColumn
2253                       from Function
2254                       where BelongsToFile = %d
2255                   """ % (FileID)
2256    ResultSet = Db.TblFile.Exec(SqlStatement)
2257    if len(ResultSet) == 0:
2258        return
2259
2260    FuncDefSet = []
2261    for Result in ResultSet:
2262        FuncDefSet.append(Result)
2263
2264
2265    FileTable = 'Identifier' + str(FileID)
2266    SqlStatement = """ select Value, ID, StartLine, StartColumn, EndLine, EndColumn
2267                       from %s
2268                       where Model = %d
2269
2270                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT)
2271    ResultSet = Db.TblFile.Exec(SqlStatement)
2272    CommentSet = []
2273    try:
2274        for Result in ResultSet:
2275            CommentSet.append(Result)
2276    except:
2277        print 'Unrecognized chars in comment of file %s', FullFileName
2278
2279
2280    for Result in CommentSet:
2281        CommentStr = Result[0]
2282        StartLine = Result[2]
2283        StartColumn = Result[3]
2284        EndLine = Result[4]
2285        EndColumn = Result[5]
2286        if not CommentStr.startswith('///<'):
2287            continue
2288
2289        Found = False
2290        for FuncDef in FuncDefSet:
2291            if StartLine == FuncDef[1] and StartColumn > FuncDef[2] and EndLine == FuncDef[3] and EndColumn < FuncDef[4]:
2292                Found = True
2293                break
2294            if StartLine > FuncDef[1] and EndLine < FuncDef[3]:
2295                Found = True
2296                break
2297            if StartLine == FuncDef[1] and StartColumn > FuncDef[2] and EndLine < FuncDef[3]:
2298                Found = True
2299                break
2300            if StartLine > FuncDef[1] and EndLine == FuncDef[3] and EndColumn < FuncDef[4]:
2301                Found = True
2302                break
2303        if Found:
2304            PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMENT_FORMAT, '', FileTable, Result[1])
2305
2306
2307def CheckFileHeaderDoxygenComments(FullFileName):
2308    ErrorMsgList = []
2309
2310    FileID = GetTableID(FullFileName, ErrorMsgList)
2311    if FileID < 0:
2312        return ErrorMsgList
2313
2314    Db = GetDB()
2315    FileTable = 'Identifier' + str(FileID)
2316    SqlStatement = """ select Value, ID
2317                       from %s
2318                       where Model = %d and (StartLine = 1 or StartLine = 7 or StartLine = 8) and StartColumn = 0
2319                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT)
2320    ResultSet = Db.TblFile.Exec(SqlStatement)
2321    if len(ResultSet) == 0:
2322        PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'No File License header appear at the very beginning of file.', 'File', FileID)
2323        return ErrorMsgList
2324
2325    NoHeaderCommentStartFlag = True
2326    NoHeaderCommentEndFlag = True
2327    NoHeaderCommentPeriodFlag = True
2328    NoCopyrightFlag = True
2329    NoLicenseFlag = True
2330    NoRevReferFlag = True
2331    NextLineIndex = 0
2332    for Result in ResultSet:
2333        FileStartFlag = False
2334        CommentStrList = []
2335        CommentStr = Result[0].strip()
2336        CommentStrListTemp = CommentStr.split('\n')
2337        if (len(CommentStrListTemp) <= 1):
2338            # For Mac
2339            CommentStrListTemp = CommentStr.split('\r')
2340        # Skip the content before the file  header
2341        for CommentLine in CommentStrListTemp:
2342            if CommentLine.strip().startswith('/** @file'):
2343                FileStartFlag = True
2344            if FileStartFlag ==  True:
2345                CommentStrList.append(CommentLine)
2346
2347        ID = Result[1]
2348        Index = 0
2349        if CommentStrList and CommentStrList[0].strip().startswith('/** @file'):
2350            NoHeaderCommentStartFlag = False
2351        else:
2352            continue
2353        if CommentStrList and CommentStrList[-1].strip().endswith('**/'):
2354            NoHeaderCommentEndFlag = False
2355        else:
2356            continue
2357
2358        for CommentLine in CommentStrList:
2359            Index = Index + 1
2360            NextLineIndex = Index
2361            if CommentLine.startswith('/** @file'):
2362                continue
2363            if CommentLine.startswith('**/'):
2364                break
2365            # Check whether C File header Comment content start with two spaces.
2366            if EccGlobalData.gConfig.HeaderCheckCFileCommentStartSpacesNum == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
2367                if CommentLine.startswith('/** @file') == False and CommentLine.startswith('**/') == False and CommentLine.strip() and CommentLine.startswith('  ') == False:
2368                    PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment content should start with two spaces at each line', FileTable, ID)
2369
2370            CommentLine = CommentLine.strip()
2371            if CommentLine.startswith('Copyright'):
2372                NoCopyrightFlag = False
2373                if CommentLine.find('All rights reserved') == -1:
2374                    for Copyright in EccGlobalData.gConfig.Copyright:
2375                        if CommentLine.find(Copyright) > -1:
2376                            PrintErrorMsg(ERROR_HEADER_CHECK_FILE, '""All rights reserved"" announcement should be following the ""Copyright"" at the same line', FileTable, ID)
2377                            break
2378                if CommentLine.endswith('<BR>') == -1:
2379                    PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'The ""<BR>"" at the end of the Copyright line is required', FileTable, ID)
2380                if NextLineIndex < len(CommentStrList) and CommentStrList[NextLineIndex].strip().startswith('Copyright') == False and CommentStrList[NextLineIndex].strip():
2381                    NoLicenseFlag = False
2382            if CommentLine.startswith('@par Revision Reference:'):
2383                NoRevReferFlag = False
2384                RefListFlag = False
2385                for RefLine in CommentStrList[NextLineIndex:]:
2386                    if RefLine.strip() and (NextLineIndex + 1) < len(CommentStrList) and CommentStrList[NextLineIndex+1].strip() and CommentStrList[NextLineIndex+1].strip().startswith('**/') == False:
2387                        RefListFlag = True
2388                    if RefLine.strip() == False or RefLine.strip().startswith('**/'):
2389                        RefListFlag = False
2390                        break
2391                    # Check whether C File header Comment's each reference at list should begin with a bullet character.
2392                    if EccGlobalData.gConfig.HeaderCheckCFileCommentReferenceFormat == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
2393                        if RefListFlag == True:
2394                            if RefLine.strip() and RefLine.strip().startswith('**/') == False and RefLine.startswith('  -') == False:
2395                                PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'Each reference on a separate line should begin with a bullet character ""-"" ', FileTable, ID)
2396
2397    if NoHeaderCommentStartFlag:
2398        PrintErrorMsg(ERROR_DOXYGEN_CHECK_FILE_HEADER, 'File header comment should begin with ""/** @file""', FileTable, ID)
2399        return
2400    if NoHeaderCommentEndFlag:
2401        PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment should end with ""**/""', FileTable, ID)
2402        return
2403    if NoCopyrightFlag:
2404        PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment missing the ""Copyright""', FileTable, ID)
2405    #Check whether C File header Comment have the License immediately after the ""Copyright"" line.
2406    if EccGlobalData.gConfig.HeaderCheckCFileCommentLicenseFormat == '1' or EccGlobalData.gConfig.HeaderCheckAll == '1' or EccGlobalData.gConfig.CheckAll == '1':
2407        if NoLicenseFlag:
2408            PrintErrorMsg(ERROR_HEADER_CHECK_FILE, 'File header comment should have the License immediately after the ""Copyright"" line', FileTable, ID)
2409
2410def CheckFuncHeaderDoxygenComments(FullFileName):
2411    ErrorMsgList = []
2412
2413    FileID = GetTableID(FullFileName, ErrorMsgList)
2414    if FileID < 0:
2415        return ErrorMsgList
2416
2417    Db = GetDB()
2418    FileTable = 'Identifier' + str(FileID)
2419    SqlStatement = """ select Value, StartLine, EndLine, ID
2420                       from %s
2421                       where Model = %d
2422                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_COMMENT)
2423
2424    ResultSet = Db.TblFile.Exec(SqlStatement)
2425    CommentSet = []
2426    try:
2427        for Result in ResultSet:
2428            CommentSet.append(Result)
2429    except:
2430        print 'Unrecognized chars in comment of file %s', FullFileName
2431
2432    # Func Decl check
2433    SqlStatement = """ select Modifier, Name, StartLine, ID, Value
2434                       from %s
2435                       where Model = %d
2436                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_DECLARATION)
2437    ResultSet = Db.TblFile.Exec(SqlStatement)
2438    for Result in ResultSet:
2439        FuncName = Result[4]
2440        FunctionHeaderComment = CheckCommentImmediatelyPrecedeFunctionHeader(Result[1], Result[2], CommentSet)
2441        if FunctionHeaderComment:
2442            CheckFunctionHeaderConsistentWithDoxygenComment(Result[0], Result[1], Result[2], FunctionHeaderComment[0], FunctionHeaderComment[1], ErrorMsgList, FunctionHeaderComment[3], FileTable)
2443        else:
2444            if EccGlobalData.gException.IsException(ERROR_HEADER_CHECK_FUNCTION, FuncName):
2445                continue
2446            ErrorMsgList.append('Line %d :Function %s has NO comment immediately preceding it.' % (Result[2], Result[1]))
2447            PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'Function [%s] has NO comment immediately preceding it.' % (FuncName), FileTable, Result[3])
2448
2449    # Func Def check
2450    SqlStatement = """ select Value, StartLine, EndLine, ID
2451                       from %s
2452                       where Model = %d
2453                   """ % (FileTable, DataClass.MODEL_IDENTIFIER_FUNCTION_HEADER)
2454
2455    ResultSet = Db.TblFile.Exec(SqlStatement)
2456    CommentSet = []
2457    try:
2458        for Result in ResultSet:
2459            CommentSet.append(Result)
2460    except:
2461        print 'Unrecognized chars in comment of file %s', FullFileName
2462
2463    SqlStatement = """ select Modifier, Header, StartLine, ID, Name
2464                       from Function
2465                       where BelongsToFile = %d
2466                   """ % (FileID)
2467    ResultSet = Db.TblFile.Exec(SqlStatement)
2468    for Result in ResultSet:
2469        FuncName = Result[4]
2470        FunctionHeaderComment = CheckCommentImmediatelyPrecedeFunctionHeader(Result[1], Result[2], CommentSet)
2471        if FunctionHeaderComment:
2472            CheckFunctionHeaderConsistentWithDoxygenComment(Result[0], Result[1], Result[2], FunctionHeaderComment[0], FunctionHeaderComment[1], ErrorMsgList, FunctionHeaderComment[3], FileTable)
2473        else:
2474            if EccGlobalData.gException.IsException(ERROR_HEADER_CHECK_FUNCTION, FuncName):
2475                continue
2476            ErrorMsgList.append('Line %d :Function [%s] has NO comment immediately preceding it.' % (Result[2], Result[1]))
2477            PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'Function [%s] has NO comment immediately preceding it.' % (FuncName), 'Function', Result[3])
2478    return ErrorMsgList
2479
2480def CheckCommentImmediatelyPrecedeFunctionHeader(FuncName, FuncStartLine, CommentSet):
2481
2482    for Comment in CommentSet:
2483        if Comment[2] == FuncStartLine - 1:
2484            return Comment
2485    return None
2486
2487def GetDoxygenStrFromComment(Str):
2488    DoxygenStrList = []
2489    ParamTagList = Str.split('@param')
2490    if len(ParamTagList) > 1:
2491        i = 1
2492        while i < len(ParamTagList):
2493            DoxygenStrList.append('@param' + ParamTagList[i])
2494            i += 1
2495
2496    Str = ParamTagList[0]
2497
2498    RetvalTagList = ParamTagList[-1].split('@retval')
2499    if len(RetvalTagList) > 1:
2500        if len(ParamTagList) > 1:
2501            DoxygenStrList[-1] = '@param' + RetvalTagList[0]
2502        i = 1
2503        while i < len(RetvalTagList):
2504            DoxygenStrList.append('@retval' + RetvalTagList[i])
2505            i += 1
2506
2507    ReturnTagList = RetvalTagList[-1].split('@return')
2508    if len(ReturnTagList) > 1:
2509        if len(RetvalTagList) > 1:
2510            DoxygenStrList[-1] = '@retval' + ReturnTagList[0]
2511        elif len(ParamTagList) > 1:
2512            DoxygenStrList[-1] = '@param' + ReturnTagList[0]
2513        i = 1
2514        while i < len(ReturnTagList):
2515            DoxygenStrList.append('@return' + ReturnTagList[i])
2516            i += 1
2517
2518    if len(DoxygenStrList) > 0:
2519        DoxygenStrList[-1] = DoxygenStrList[-1].rstrip('--*/')
2520
2521    return DoxygenStrList
2522
2523def CheckGeneralDoxygenCommentLayout(Str, StartLine, ErrorMsgList, CommentId= -1, TableName=''):
2524    #/** --*/ @retval after @param
2525    if not Str.startswith('/**'):
2526        ErrorMsgList.append('Line %d : Comment does NOT have prefix /** ' % StartLine)
2527        PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Comment does NOT have prefix /** ', TableName, CommentId)
2528    if not Str.endswith('**/'):
2529        ErrorMsgList.append('Line %d : Comment does NOT have tail **/ ' % StartLine)
2530        PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Comment does NOT have tail **/ ', TableName, CommentId)
2531    FirstRetvalIndex = Str.find('@retval')
2532    LastParamIndex = Str.rfind('@param')
2533    if (FirstRetvalIndex > 0) and (LastParamIndex > 0) and (FirstRetvalIndex < LastParamIndex):
2534        ErrorMsgList.append('Line %d : @retval appear before @param ' % StartLine)
2535        PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, @retval appear before @param  ', TableName, CommentId)
2536
2537def CheckFunctionHeaderConsistentWithDoxygenComment(FuncModifier, FuncHeader, FuncStartLine, CommentStr, CommentStartLine, ErrorMsgList, CommentId= -1, TableName=''):
2538
2539    ParamList = GetParamList(FuncHeader)
2540    CheckGeneralDoxygenCommentLayout(CommentStr, CommentStartLine, ErrorMsgList, CommentId, TableName)
2541    DescriptionStr = CommentStr
2542    DoxygenStrList = GetDoxygenStrFromComment(DescriptionStr)
2543    if DescriptionStr.find('.') == -1:
2544        PrintErrorMsg(ERROR_DOXYGEN_CHECK_COMMENT_DESCRIPTION, 'Comment description should end with period \'.\'', TableName, CommentId)
2545    DoxygenTagNumber = len(DoxygenStrList)
2546    ParamNumber = len(ParamList)
2547    for Param in ParamList:
2548        if Param.Name.upper() == 'VOID' and ParamNumber == 1:
2549            ParamNumber -= 1
2550    Index = 0
2551    if ParamNumber > 0 and DoxygenTagNumber > 0:
2552        while Index < ParamNumber and Index < DoxygenTagNumber:
2553            ParamModifier = ParamList[Index].Modifier
2554            ParamName = ParamList[Index].Name.strip()
2555            Tag = DoxygenStrList[Index].strip(' ')
2556            if (not Tag[-1] == ('\n')) and (not Tag[-1] == ('\r')):
2557                ErrorMsgList.append('Line %d : in Comment, <%s> does NOT end with new line ' % (CommentStartLine, Tag.replace('\n', '').replace('\r', '')))
2558                PrintErrorMsg(ERROR_HEADER_CHECK_FUNCTION, 'in Comment, <%s> does NOT end with new line ' % (Tag.replace('\n', '').replace('\r', '')), TableName, CommentId)
2559            TagPartList = Tag.split()
2560            if len(TagPartList) < 2:
2561                ErrorMsgList.append('Line %d : in Comment, <%s> does NOT contain doxygen contents ' % (CommentStartLine, Tag.replace('\n', '').replace('\r', '')))
2562                PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT contain doxygen contents ' % (Tag.replace('\n', '').replace('\r', '')), TableName, CommentId)
2563                Index += 1
2564                continue
2565            LBPos = Tag.find('[')
2566            RBPos = Tag.find(']')
2567            ParamToLBContent = Tag[len('@param'):LBPos].strip()
2568            if LBPos > 0 and len(ParamToLBContent) == 0 and RBPos > LBPos:
2569                InOutStr = ''
2570                ModifierPartList = ParamModifier.split()
2571                for Part in ModifierPartList:
2572                    if Part.strip() == 'IN':
2573                        InOutStr += 'in'
2574                    if Part.strip() == 'OUT':
2575                        if InOutStr != '':
2576                            InOutStr += ', out'
2577                        else:
2578                            InOutStr = 'out'
2579
2580                if InOutStr != '':
2581                    if Tag.find('[' + InOutStr + ']') == -1:
2582                        if InOutStr != 'in, out':
2583                            ErrorMsgList.append('Line %d : in Comment, <%s> does NOT have %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'))
2584                            PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT have %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'), TableName, CommentId)
2585                        else:
2586                            if Tag.find('[in,out]') == -1:
2587                                ErrorMsgList.append('Line %d : in Comment, <%s> does NOT have %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'))
2588                                PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT have %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), '[' + InOutStr + ']'), TableName, CommentId)
2589
2590
2591            if Tag.find(ParamName) == -1 and ParamName != 'VOID' and ParamName != 'void':
2592                ErrorMsgList.append('Line %d : in Comment, <%s> does NOT consistent with parameter name %s ' % (CommentStartLine, (TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), ParamName))
2593                PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'in Comment, <%s> does NOT consistent with parameter name %s ' % ((TagPartList[0] + ' ' + TagPartList[1]).replace('\n', '').replace('\r', ''), ParamName), TableName, CommentId)
2594            Index += 1
2595
2596        if Index < ParamNumber:
2597            ErrorMsgList.append('Line %d : Number of doxygen tags in comment less than number of function parameters' % CommentStartLine)
2598            PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Number of doxygen tags in comment less than number of function parameters ', TableName, CommentId)
2599        # VOID return type, NOT VOID*. VOID* should be matched with a doxygen tag.
2600        if (FuncModifier.find('VOID') != -1 or FuncModifier.find('void') != -1) and FuncModifier.find('*') == -1:
2601
2602            # assume we allow a return description tag for void func. return. that's why 'DoxygenTagNumber - 1' is used instead of 'DoxygenTagNumber'
2603            if Index < DoxygenTagNumber - 1 or (Index < DoxygenTagNumber and DoxygenStrList[Index].startswith('@retval')):
2604                ErrorMsgList.append('Line %d : VOID return type need NO doxygen tags in comment' % CommentStartLine)
2605                PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'VOID return type need no doxygen tags in comment ', TableName, CommentId)
2606        else:
2607            if Index < DoxygenTagNumber and not DoxygenStrList[Index].startswith('@retval') and not DoxygenStrList[Index].startswith('@return'):
2608                ErrorMsgList.append('Line %d : Number of @param doxygen tags in comment does NOT match number of function parameters' % CommentStartLine)
2609                PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'Number of @param doxygen tags in comment does NOT match number of function parameters ', TableName, CommentId)
2610    else:
2611        if ParamNumber == 0 and DoxygenTagNumber != 0 and ((FuncModifier.find('VOID') != -1 or FuncModifier.find('void') != -1) and FuncModifier.find('*') == -1):
2612            ErrorMsgList.append('Line %d : VOID return type need NO doxygen tags in comment' % CommentStartLine)
2613            PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'VOID return type need NO doxygen tags in comment ', TableName, CommentId)
2614        if ParamNumber != 0 and DoxygenTagNumber == 0:
2615            ErrorMsgList.append('Line %d : No doxygen tags in comment' % CommentStartLine)
2616            PrintErrorMsg(ERROR_DOXYGEN_CHECK_FUNCTION_HEADER, 'No doxygen tags in comment ', TableName, CommentId)
2617
2618if __name__ == '__main__':
2619
2620#    EdkLogger.Initialize()
2621#    EdkLogger.SetLevel(EdkLogger.QUIET)
2622#    CollectSourceCodeDataIntoDB(sys.argv[1])
2623    try:
2624        test_file = sys.argv[1]
2625    except IndexError, v:
2626        print "Usage: %s filename" % sys.argv[0]
2627        sys.exit(1)
2628    MsgList = CheckFuncHeaderDoxygenComments(test_file)
2629    for Msg in MsgList:
2630        print Msg
2631    print 'Done!'
2632