--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/srcanamdw/codescanner/scripts/linescanner.py Thu Feb 18 12:29:02 2010 +0530
@@ -0,0 +1,1885 @@
+# #################################################################
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+# * Neither the name of Nokia Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#
+#
+# linescanner.py - the main body of CodeScanner
+#
+# #################################################################
+
+import base64
+import datetime
+import encodings
+import getopt
+import os
+import os.path
+import psyco
+import re
+import sys
+import xml.dom.minidom
+import zlib
+
+# Ignore flags
+KIgnoreNothing = 0
+KIgnoreComments = 1
+KIgnoreCommentsAndQuotes = 2
+KIgnoreQuotes = 3
+
+# Severities for the scripts
+KSeverityHigh = 0
+KSeverityMedium = 1
+KSeverityLow = 2
+
+# The names used in the XML configuration file for severity element names.
+KSeverityConfigMap = {
+ KSeverityHigh : "high",
+ KSeverityMedium : "medium",
+ KSeverityLow : "low"}
+
+# The names used in the HTML summary file for severity element names.
+KSeverityHTMLMap = {
+ KSeverityHigh : "High",
+ KSeverityMedium : "Medium",
+ KSeverityLow : "Low"}
+
+# Categories for the scripts
+KCategoryLegal = "Legal Code"
+KCategoryDefinitePanic = "Always Panic"
+KCategoryCanPanic = "Can Panic"
+KCategoryWrongFunctionality = "Wrong Functionality"
+KCategoryLocalisation = "Localisation"
+KCategoryPerformance = "Performance"
+KCategoryCodingStandards = "Coding Standard"
+KCategoryDocumentation = "Documentation"
+KCategoryCodeReviewGuides = "Code Review Guide"
+KCategoryOther = "Other"
+
+KCategoryHtmlDisplayOrder = [KCategoryLegal,
+ KCategoryDefinitePanic,
+ KCategoryCanPanic,
+ KCategoryWrongFunctionality,
+ KCategoryLocalisation,
+ KCategoryPerformance,
+ KCategoryCodingStandards,
+ KCategoryDocumentation,
+ KCategoryCodeReviewGuides,
+ KCategoryOther]
+
+# The names used in the XML configuration file for category element names.
+KCategoryConfigMap = {
+ KCategoryLegal : "legal",
+ KCategoryDefinitePanic : "panic",
+ KCategoryCanPanic : "canpanic",
+ KCategoryWrongFunctionality : "functionality",
+ KCategoryLocalisation : "localisation",
+ KCategoryPerformance : "performance",
+ KCategoryCodingStandards : "codingstandards",
+ KCategoryDocumentation : "documentation",
+ KCategoryCodeReviewGuides : "codereview",
+ KCategoryOther : "other"}
+
+#Custom rule keyword types
+KKeywordBaseClass = "baseclass"
+KKeywordCall = "call"
+KKeywordClassName = "class"
+KKeywordComment = "comment"
+KKeywordGeneric = "generic"
+KKeywordLocal = "local"
+KKeywordMacro = "macro"
+KKeywordMember = "member"
+KKeywordMethod = "method"
+KKeywordParameter = "parameter"
+KKeywordUnknown = "unknown"
+
+#The names used in the XML configuration file for custom rule keyword types.
+KCustomRuleKeywordMap = {
+ KKeywordBaseClass : "baseclass",
+ KKeywordCall : "call",
+ KKeywordClassName : "class",
+ KKeywordComment : "comment",
+ KKeywordGeneric : "generic",
+ KKeywordLocal : "local",
+ KKeywordMacro : "macro",
+ KKeywordMember : "member",
+ KKeywordMethod : "method",
+ KKeywordParameter : "parameter",
+ KKeywordUnknown : "unknown"}
+
+KVersion = "Nokia CodeScanner version 2.1.4"
+KCopyrightLine1 = "Copyright (c) 2007-2009. Nokia Corporation. All rights reserved."
+KCopyrightLine1Html = "Copyright © 2007-2009. Nokia Corporation. All rights reserved."
+KCopyrightLine2 = "For product and support information, visit www.forum.nokia.com."
+KWww = "www.forum.nokia.com"
+
+stringPool = {}
+#!LOCALISEHERE
+
+def Usage(code, msg=""):
+ print msg
+ print
+ print KVersion
+ print
+ print "Usage: CodeScanner [options] <source dir> [<output dir>]"
+ print " or: CodeScanner [options] <source file> [<output dir>]"
+ print
+ print "options:"
+ print " -h - display command help"
+ print " -v - display verbose messages"
+ print " -c <config file> - use specified configuration file"
+ print " -i <source dir/file> - specify additional directory/file to scan"
+ print " -l <log file> - create debug log with specified filename"
+ print " -o html|xml|std - specify output format : HTML, XML or StdOut; default is HTML"
+ print " -x url to lxr site"
+ print " -r lxr version"
+ print " -t on/off - create a time-stamped directory for results, default is on"
+ print
+ print "<source dir> is the directory containing the source code to scan"
+ print "<source file> is the single file containing the source code to scan"
+ print "<output dir> is the directory in which to produce the output"
+ print
+ print "Notes:"
+ print "<source dir> and <output dir> cannot be identical"
+ print "<output dir> cannot be the root of a drive"
+ print
+ print KCopyrightLine1
+ print KCopyrightLine2
+ if scanner.iLog <> None:
+ scanner.iLog.Write("usage(): exiting with code " + str(code))
+ scanner.iLog.Close()
+ sys.exit(code)
+
+def DefaultCompare(aLines, aCurrentline, aRematch, aFilename):
+ if aRematch.search(aLines[aCurrentline]):
+ return 1
+ else:
+ return 0
+
+def DefaultFuncParamCompare(lines, currentline, rematch, filename):
+ # distinguish local declaration from function parameter
+ line = lines[currentline]
+ m = rematch.search(line)
+ if m:
+ isFuncParam = (line.find(")") <> -1)
+ isLocal = (line.find(";") <> -1)
+
+ while (not isFuncParam) and (not isLocal) and (currentline + 1 < len(lines)):
+ currentline += 1
+ line = lines[currentline]
+ isFuncParam = (line.find(")") <> -1)
+ isLocal = (line.find(";") <> -1)
+
+ if isFuncParam:
+ return 1
+ elif isLocal:
+ return 0
+
+ return 0
+
+def ScanDirOrFile(argument):
+ if os.path.isdir(argument):
+ scanner.iComponentManager.SetRoot(argument)
+ scanner.TraverseDirectory(argument)
+ elif os.path.isfile(argument):
+ parentDir = os.path.dirname(argument)
+ scanner.iComponentManager.SetRoot(parentDir)
+ scanner.iComponentManager.BeginDirectory(parentDir)
+ numberOfLinesScanned = 0
+ numberOfLinesScanned += scanner.ScanFile(argument)
+ scanner.iComponentManager.EndDirectory(parentDir, numberOfLinesScanned)
+ else:
+ print "Unable to open specified source file: " + argument
+ sys.exit(2)
+
+
+class CScript:
+
+ # #######################################################
+ # CScript - a test script
+
+ def __init__(self, aScriptName):
+ self.iScriptName = aScriptName
+ self.iCompare = DefaultCompare
+ self.iReString = ""
+ self.iReMatch = re.compile("")
+ self.iTitle = stringPool[aScriptName + "!title"]
+ self.iIdeTitle = stringPool[aScriptName + "!ideTitle"]
+ self.iFileExts = []
+ self.iIgnore = KIgnoreNothing
+ self.iDescription = stringPool[aScriptName + "!description"]
+ self.iSeverity = KSeverityMedium
+ self.iBaseClass = ""
+
+ def ScriptConfig(self):
+ if (scanner.iDomConfig <> None):
+ for scriptsNode in scanner.iDomConfig.getElementsByTagName("scripts"):
+ for scriptNode in scriptsNode.getElementsByTagName(self.iScriptName):
+ return scriptNode
+ return None
+
+ def DefaultInheritanceCompare(self, lines, currentline, rematch, filename):
+ m = rematch.search(lines[currentline])
+ if m:
+ inheritanceString = m.group(3)
+ # check for inheritance list spanning multiple lines
+ i = currentline + 1
+ while (inheritanceString.find("{") == -1) and i < len(lines):
+ if (inheritanceString.find(";") <> -1):
+ return 0
+ inheritanceString += lines[i]
+ i += 1
+
+ # construct inheritance class list
+ inheritancelist = inheritanceString.split(",")
+ reclass = re.compile("[\s:]*(public|protected|private)?\s*([\w:]+)")
+ classlist = []
+ for inheritance in inheritancelist:
+ match = reclass.search(inheritance)
+ if match:
+ inheritclass = match.group(2)
+ colonpos = inheritclass.rfind(":")
+ if (colonpos <> -1):
+ inheritclass = inheritclass[colonpos + 1:]
+ classlist.append(inheritclass)
+
+ # search for inheritance class
+ for classname in classlist:
+ if classname == self.iBaseClass:
+ return 1
+
+ return 0
+
+
+class CCustomScript(CScript):
+
+ # #######################################################
+ # CScript - a test script based on a custom rule
+
+ def __init__(self, aScriptName):
+ self.iScriptName = aScriptName
+ self.iCompare = DefaultCompare
+ self.iReString = ""
+ self.iTitle = ""
+ self.iIdeTitle = ""
+ self.iFileExts = []
+ self.iIgnore = KIgnoreNothing
+ self.iDescription = ""
+
+
+class CCategorisedScripts:
+
+ # #######################################################
+ # CCategorisedScripts - a collection of scripts sorted
+ # by script category (panic, can panic, etc.)
+
+ def AddScript(self, aScript):
+ # do we have a category for this already?
+ category = aScript.iCategory
+ if (not self.iScripts.has_key(category)):
+ # no, create a linear array here
+ self.iScripts[category] = []
+
+ # append to the correct category
+ self.iScripts[category].append(aScript)
+
+ # compile the reg-ex otherwise will get continuous hits
+ aScript.iReMatch = re.compile(aScript.iReString, re.VERBOSE)
+
+ def AllScripts(self):
+ result = []
+ for scripts in self.iScripts.values():
+ result += scripts
+
+ return result
+
+ def PrintListOfTestScripts(self):
+ for category in self.iScripts.keys():
+ print(category + "\n----------------------------------")
+ for script in self.iScripts[category]:
+ print("\t" + script.iScriptName)
+
+ print("")
+
+ # iScripts is a 2D array, 1st level is a hash of categories
+ # 2nd level is linear array
+ iScripts = {}
+
+class CLogger:
+
+ # #######################################################
+ # CLogger
+ # a simple log file interface
+
+ def __init__(self, aFilename):
+ if aFilename != None and len(aFilename) > 0:
+ self.iFile = file(aFilename, "w")
+ self.iFile.write(KVersion + " started at " + datetime.datetime.now().ctime() + "\n")
+ else:
+ self.iFile = None
+
+ def Write(self, aText):
+ if self.iFile <> None:
+ self.iFile.write(str(datetime.datetime.now().time())+":"+aText+"\n")
+ self.iFile.flush()
+
+ def Close(self):
+ if self.iFile <> None:
+ self.iFile.write(KVersion + " ended at " + datetime.datetime.now().ctime() + "\n")
+ self.iFile.close()
+
+
+class CRendererBase:
+
+ # #######################################################
+ # CRendererBase - base class for renderers
+
+ def RegisterSelf(self, aName, aDescription, aRendererManager):
+ self.iName = aName
+ self.iDescription = aDescription
+ aRendererManager.AddRenderer(self)
+ def BeginComponent(self, aComponent):
+ return
+ def BeginFile(self, aFilename):
+ return
+ def ReportError(self, aLineContext, aScript):
+ return
+ def EndFile(self):
+ return
+ def EndComponent(self, aComponent):
+ return
+
+
+class CStdOutRenderer(CRendererBase):
+
+ # #######################################################
+ # CStdOutRenderer - renderer for Standard Console Output
+ # Output goes to standard output; when run in Carbide,
+ # this shows up in the output window. Correctly formatted
+ # lines can then be selected, automatically selecting
+ # the corresponding line of the associated source file.
+ # The format is:
+ # <filename>(<line>) : <comment>
+
+ def __init__(self, aRendererManager):
+ self.RegisterSelf("stdout", "StdOut renderer", aRendererManager)
+ print KVersion
+
+ def BeginComponent(self, aComponent):
+ return
+
+ def BeginFile(self, aFilename):
+ self.iErrorCount = 0
+ scanner.ReportAction("Scanning file " + aFilename)
+
+ def ReportError(self, aLineContext, aScript):
+ self.iErrorCount += 1
+ if (aScript.iSeverity == KSeverityLow):
+ msgType = "info"
+ elif (aScript.iSeverity == KSeverityMedium):
+ msgType = "warning"
+ elif (aScript.iSeverity == KSeverityHigh):
+ msgType = "error"
+ print(aLineContext.iFileName + "(" + str(aLineContext.iLineNumber) + ") : " + msgType + ": " + aScript.iScriptName + ": " + KSeverityConfigMap[aScript.iSeverity] + ": " + KCategoryConfigMap[aScript.iCategory] + ": " + aScript.iIdeTitle)
+ if len(scanner.iRendererManager.iAnnotation)>0:
+ print scanner.iRendererManager.iAnnotation
+ scanner.iRendererManager.iAnnotation = ""
+
+ def EndFile(self):
+ scanner.ReportAction("Total problems found in file: " + str(self.iErrorCount))
+
+ def EndComponent(self, aComponent):
+ scanner.iEndTime = datetime.datetime.now().ctime()
+ return
+
+
+class CXmlComponentSummaryFile:
+ # #########################################################
+ # CXmlComponentSummaryFile
+ # Encapsulates the script (problem) summary for XML output.
+ # For each script, there is a listing for occurrences
+ # of that script's problem and location of each occurrence.
+
+ def CreateSummary(self, aXmlRenderer):
+ try:
+ outputPath = os.path.normpath(os.path.join(aXmlRenderer.iOutputDirectory, "problemIndex.xml"))
+ outputFile = file(outputPath, "w")
+ except IOError:
+ scanner.ReportError("IOError : Unable to create output file " + outputPath)
+ else:
+ errors = aXmlRenderer.iErrors
+ level = 0
+ indent = " "
+ outputFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+ outputFile.write(level * indent + "<problemIndex>\n")
+ level += 1
+ for category in KCategoryHtmlDisplayOrder:
+ found = False
+ if scanner.iCategoriedScripts.iScripts.has_key(category):
+ for script in scanner.iCategoriedScripts.iScripts[category]:
+ if errors.has_key(script.iScriptName):
+ found = True
+ break
+ if found:
+ outputFile.write(level * indent + "<category")
+ outputFile.write(" name=\"" + KCategoryConfigMap[category] + "\">\n")
+ level += 1
+ for script in scanner.iCategoriedScripts.iScripts[category]:
+ if errors.has_key(script.iScriptName):
+ outputFile.write(level * indent + "<problem")
+ outputFile.write(" name=\"" + script.iScriptName + "\"")
+ outputFile.write(" severity=\"" + KSeverityConfigMap[script.iSeverity] + "\">\n")
+ level += 1
+ for fileName, lines in errors[script.iScriptName].items():
+ outputFile.write(level * indent + "<file")
+ outputFile.write(" path=\"" + fileName + "\">\n")
+ level += 1
+ for lineNo in lines:
+ outputFile.write(level * indent + str(lineNo) + "\n")
+ level -= 1
+ outputFile.write(level * indent + "</file>\n")
+ level -= 1
+ outputFile.write(level * indent + "</problem>\n")
+ level -= 1
+ outputFile.write(level * indent + "</category>\n")
+ level -= 1
+ outputFile.write(level * indent + "</problemIndex>\n")
+ outputFile.close()
+
+
+class CXmlRenderer(CRendererBase):
+
+ # ########################################
+ # CXmlRenderer - a renderer for XML output
+
+ def __init__(self, aRendererManager, aOutputDirectory):
+ self.RegisterSelf("xml", "XML renderer", aRendererManager)
+ self.iOutputDirectory = aOutputDirectory
+ if os.path.isdir(self.iOutputDirectory) != True :
+ os.makedirs(self.iOutputDirectory)
+ self.iErrors = {}
+ print
+ print KVersion
+ print KCopyrightLine1
+ print KCopyrightLine2
+
+ def BeginComponent(self, aComponent):
+ return
+
+ def BeginFile(self, aFilename):
+ self.iFilename = aFilename
+ scanner.ReportAction("Scanning file " + aFilename)
+
+ def ReportError(self, aLineContext, aScript):
+ scriptName = aScript.iScriptName
+ fileName = aLineContext.iFileName
+ lineNumber = aLineContext.iLineNumber
+ if (not self.iErrors.has_key(scriptName)):
+ self.iErrors[scriptName] = {}
+ if (not self.iErrors[scriptName].has_key(fileName)):
+ self.iErrors[scriptName][fileName] = []
+ self.iErrors[scriptName][fileName].append(lineNumber)
+
+ def EndFile(self):
+ #tbd
+ return
+
+ def EndComponent(self, aComponent):
+ relativeComponentName = scanner.iComponentManager.RelativeComponentName(aComponent.iFullPath)
+ if len(relativeComponentName) < 1: # root component - final component
+ scanner.iEndTime = datetime.datetime.now().ctime()
+ componentSummaryFile = CXmlComponentSummaryFile()
+ componentSummaryFile.CreateSummary(self)
+
+
+class CHtmlOutputFileBase:
+
+ # #######################################################
+ # CHtmlOutputFileBase - base class for HTML output files
+
+ def WriteHeader(self, aOutputFile):
+ aOutputFile.write("<html><body>")
+
+ def Write(self, aOutputFile, aText):
+ aOutputFile.write(aText)
+
+ def WriteLink(self, aOutputFile, aHref, aText):
+ aHref = self.CleanupLink(aHref)
+ aOutputFile.write("<a href=\"" + aHref + "\">" + aText + "</a>")
+
+ def WriteElement(self, aOutputFile, aElementName, aElementValue):
+ aOutputFile.write("<"+aElementName+">"+aElementValue+"</"+aElementName+">")
+
+ def WriteBreak(self, aOutputFile):
+ aOutputFile.write("<br>")
+
+ def WriteFooter(self, aOutputFile):
+ aOutputFile.write("<br><hr><center><h5>"+KCopyrightLine1Html+"</h5>")
+ aOutputFile.write("<h5>")
+ CHtmlOutputFileBase.WriteLink(self, aOutputFile, "http://"+KWww, KWww)
+ aOutputFile.write("</h5></center></body></html>")
+
+ def CleanupLink(self, aHref):
+ # Mozilla Firefox does not handle link with the '#' character correctly,
+ # so we need to replace it with the equivalent URL encoding "%23"
+ aHref = aHref.replace("#", "%23")
+ # Mozilla Firefox sometimes does not handle link with '\' correctly,
+ # so we need to replace it with '/'
+ aHref = aHref.replace('\\', '/')
+ return aHref
+
+
+class CHtmlOutputFile(CHtmlOutputFileBase):
+
+ # #######################################################
+ # CHtmlOutputFile - simplified access to HTML output file
+
+ def __init__(self, aOutputPath):
+ if not os.path.isdir(os.path.dirname(aOutputPath)):
+ os.makedirs(os.path.dirname(aOutputPath))
+ self.iOutputFile = file(aOutputPath, "w")
+ self.WriteHeader(self.iOutputFile)
+
+ def Write(self, aText):
+ CHtmlOutputFileBase.Write(self, self.iOutputFile, aText)
+
+ def WriteLink(self, aHref, aText):
+ CHtmlOutputFileBase.WriteLink(self, self.iOutputFile, aHref, aText)
+
+ def WriteElement(self, aElementName, aElementValue):
+ CHtmlOutputFileBase.WriteElement(self, self.iOutputFile, aElementName, aElementValue)
+
+ def WriteBreak(self):
+ CHtmlOutputFileBase.WriteBreak(self, self.iOutputFile)
+
+ def Close(self):
+ self.WriteFooter(self.iOutputFile)
+ self.iOutputFile.close()
+
+
+class CHtmlComponentSummaryFiles:
+
+ # #######################################################
+ # CHtmlComponentSummaryFiles
+ # Encapsulates the component summary files for HTML output.
+ # For each component, there is a component report file listing the number
+ # of occurrences of each problem type. There is also a single index or
+ # summary file with links to each of the component report files.
+
+ def CreateSummaries(self, aHtmlRenderer, aOutputDirectory):
+ totalErrorCount = 0
+ outputPath = os.path.normpath(os.path.join(aOutputDirectory, "componentIndex.html"))
+ componentSummaryFile = CHtmlOutputFile(outputPath)
+ componentSummaryFile.Write("<font face=verdana>")
+ componentSummaryFile.WriteElement("h2", "Component Summary")
+ componentSummaryFile.Write("Source: "+scanner.iSource)
+ componentSummaryFile.WriteBreak()
+ componentSummaryFile.Write("Scan started at: " + scanner.iStartTime)
+ componentSummaryFile.WriteBreak()
+ componentSummaryFile.Write("Scan completed at: " + scanner.iEndTime)
+ componentSummaryFile.WriteBreak()
+ componentSummaryFile.WriteBreak()
+ componentSummaryFile.WriteLink("problemIndex.html", "View problems by type")
+ componentSummaryFile.WriteBreak()
+ componentSummaryFile.Write("<hr>")
+ componentSummaryFile.WriteBreak()
+ componentSummaryFile.Write("<table border=\"1\" width=\"100%\">")
+ componentSummaryFile.Write("<tr bgcolor=\"#0099ff\">")
+ componentSummaryFile.WriteElement("th width=\"75%\"", "Component")
+ componentSummaryFile.WriteElement("th", "Items Found")
+ componentSummaryFile.WriteElement("th", "Lines of Code")
+ componentSummaryFile.WriteElement("th", "Possible Defects/KLOC")
+ componentSummaryFile.Write("</tr>")
+ for component in scanner.iComponentManager.iCompletedComponents:
+ componentName = scanner.iComponentManager.ComponentName(component.iFullPath)
+ outputPath = os.path.normpath(os.path.join(aOutputDirectory, "byComponent"))
+ outputPath = os.path.normpath(os.path.join(outputPath, componentName))
+ outputPath = os.path.normpath(os.path.join(outputPath, "componentSummary.html"))
+ errorCount = self.WriteComponentReport(aHtmlRenderer, outputPath, component.iFullPath, componentName)
+ if (errorCount > 0):
+ totalErrorCount = totalErrorCount + errorCount
+ numberOfLinesScanned = component.iNumberOfLinesScanned
+ if (numberOfLinesScanned > 0):
+ defectsPerKLOC = int((1000.0 / numberOfLinesScanned) * errorCount)
+ else:
+ defectsPerKLOC = 0
+ componentSummaryFile.Write("<tr>")
+ componentSummaryFile.Write("<td>")
+ relOutputPath = os.path.normpath(os.path.join("byComponent", componentName))
+ relOutputPath = os.path.normpath(os.path.join(relOutputPath, "componentSummary.html"))
+ componentSummaryFile.WriteLink(relOutputPath, component.iFullPath)
+ componentSummaryFile.Write("</td>")
+ componentSummaryFile.Write("<td>")
+ componentSummaryFile.WriteElement("center",str(errorCount))
+ componentSummaryFile.Write("</td>")
+ componentSummaryFile.Write("<td>")
+ componentSummaryFile.WriteElement("center",str(numberOfLinesScanned))
+ componentSummaryFile.Write("</td>")
+ componentSummaryFile.Write("<td>")
+ componentSummaryFile.WriteElement("center",str(defectsPerKLOC))
+ componentSummaryFile.Write("</td>")
+ componentSummaryFile.Write("</tr>")
+
+ componentSummaryFile.Write("<tr>")
+ componentSummaryFile.Write("<td>")
+ componentSummaryFile.WriteElement("b", "Total")
+ componentSummaryFile.Write("</td>")
+ componentSummaryFile.Write("<td><center>")
+ componentSummaryFile.WriteElement("b", str(totalErrorCount))
+ componentSummaryFile.Write("</center></td>")
+ componentSummaryFile.Write("</tr>")
+
+ componentSummaryFile.Write("</table>")
+ componentSummaryFile.Close()
+
+ def WriteComponentReport(self, aHtmlRenderer, aOutputPath, aComponentFullPath, aComponentName):
+ totalErrorCount = 0
+ componentReportFile = CHtmlOutputFile(aOutputPath)
+ componentReportFile.Write("<font face=verdana>")
+ componentReportFile.WriteElement("h2", "Component Report")
+ componentReportFile.WriteElement("h3", "Component: "+aComponentFullPath)
+ componentReportFile.Write("<font face=verdana color=black>")
+ found = False
+ for category in KCategoryHtmlDisplayOrder:
+ if scanner.iCategoriedScripts.iScripts.has_key(category):
+ for script in scanner.iCategoriedScripts.iScripts[category]:
+ errorCount = scanner.iComponentManager.ScriptComponentErrorCount(aComponentFullPath, script.iScriptName)
+ if errorCount > 0:
+ found = True
+ break
+
+ if found:
+ componentReportFile.Write("<table border=\"1\" width=\"100%\">")
+ componentReportFile.Write("<tr bgcolor=\"#0099ff\">")
+ componentReportFile.WriteElement("th width=\"75%\"", "Problem")
+ componentReportFile.WriteElement("th", "Items Found")
+ componentReportFile.WriteElement("th", "Severity")
+ componentReportFile.Write("</tr>")
+ for category in KCategoryHtmlDisplayOrder:
+ if scanner.iCategoriedScripts.iScripts.has_key(category):
+ for script in scanner.iCategoriedScripts.iScripts[category]:
+ errorCount = scanner.iComponentManager.ScriptComponentErrorCount(aComponentFullPath, script.iScriptName)
+ if errorCount > 0:
+ componentReportFile.Write("<tr>")
+ componentReportFile.Write("<td>")
+ #scriptComponentPath = aHtmlRenderer.ScriptComponentPath(aComponentFullPath, script.iScriptName)
+ #componentReportFile.WriteLink(scriptComponentPath, script.iTitle)
+ componentReportFile.WriteLink(script.iScriptName+".html", script.iTitle)
+ componentReportFile.Write("</td>")
+ componentReportFile.Write("<td>")
+ componentReportFile.WriteElement("center", str(errorCount))
+ componentReportFile.Write("</td>")
+ componentReportFile.Write("<td>")
+ componentReportFile.WriteElement("center", KSeverityHTMLMap[script.iSeverity])
+ componentReportFile.Write("</td>")
+ componentReportFile.Write("</tr>")
+ totalErrorCount = totalErrorCount + errorCount
+ componentReportFile.Write("<tr>")
+ componentReportFile.Write("<td>")
+ componentReportFile.WriteElement("b", "Total")
+ componentReportFile.Write("</td>")
+ componentReportFile.Write("<td><center>")
+ componentReportFile.WriteElement("b", str(totalErrorCount))
+ componentReportFile.Write("</center></td>")
+ componentReportFile.Write("</tr>")
+ componentReportFile.Write("</table>")
+ else:
+ componentReportFile.WriteBreak()
+ componentReportFile.WriteElement("i", "There are no items to report for this component.")
+ componentReportFile.WriteBreak()
+ componentReportFile.Close()
+ return totalErrorCount
+
+
+class CHtmlScriptSummaryFiles:
+
+ # #######################################################
+ # CHtmlScriptSummaryFiles
+ # Encapsulates the script (problem) summary files for HTML output.
+ # For each script, there is a file listing the number of occurrences
+ # of that script's problem for each component. There is also a single
+ # index or summary file with links to each of the problem report file.
+
+ def CreateSummaries(self, aHtmlRenderer, aOutputDirectory):
+
+ totalErrorCount = 0
+
+ outputPath = os.path.normpath(os.path.join(aOutputDirectory, "problemIndex.html"))
+ scriptSummaryFile = CHtmlOutputFile(outputPath)
+ scriptSummaryFile.Write("<font face=verdana>")
+ scriptSummaryFile.WriteElement("h2", "Problem Summary")
+ scriptSummaryFile.Write("Source: "+scanner.iSource)
+ scriptSummaryFile.WriteBreak()
+ scriptSummaryFile.Write("Scan started at: " + scanner.iStartTime)
+ scriptSummaryFile.WriteBreak()
+ scriptSummaryFile.Write("Scan completed at: " + scanner.iEndTime)
+ scriptSummaryFile.WriteBreak()
+ scriptSummaryFile.WriteBreak()
+ scriptSummaryFile.WriteLink("componentIndex.html", "View problems by component")
+ scriptSummaryFile.WriteBreak()
+ scriptSummaryFile.Write("<hr>")
+ scriptSummaryFile.WriteBreak()
+ for category in KCategoryHtmlDisplayOrder:
+ if scanner.iCategoriedScripts.iScripts.has_key(category):
+ scriptSummaryFile.WriteElement("h3", "Category: "+category)
+ scriptSummaryFile.Write("<table border=\"1\" width=\"100%\">")
+ scriptSummaryFile.Write("<tr bgcolor=\"#0099ff\">")
+ scriptSummaryFile.WriteElement("th width=\"75%\"", "Problem")
+ scriptSummaryFile.WriteElement("th", "Items Found")
+ scriptSummaryFile.WriteElement("th", "Severity")
+ scriptSummaryFile.Write("</tr>")
+ categoryErrorCount = 0
+ for script in scanner.iCategoriedScripts.iScripts[category]:
+ outputPath = os.path.normpath(os.path.join(aOutputDirectory, "byProblem"))
+ outputPath = os.path.normpath(os.path.join(outputPath, script.iScriptName+"Summary.html"))
+ errorCount = self.WriteScriptReport(aHtmlRenderer, outputPath, script)
+ categoryErrorCount = categoryErrorCount + errorCount
+ scriptSummaryFile.Write("<tr>")
+ scriptSummaryFile.Write("<td>")
+ relOutputPath = os.path.normpath(os.path.join("byProblem", script.iScriptName+"Summary.html"))
+ scriptSummaryFile.WriteLink(relOutputPath, script.iTitle)
+ scriptSummaryFile.Write("</td>")
+ scriptSummaryFile.Write("<td>")
+ scriptSummaryFile.WriteElement("center", str(errorCount))
+ scriptSummaryFile.Write("</td>")
+ scriptSummaryFile.Write("<td>")
+ scriptSummaryFile.WriteElement("center", KSeverityHTMLMap[script.iSeverity])
+ scriptSummaryFile.Write("</td>")
+ scriptSummaryFile.Write("</tr>")
+ totalErrorCount = totalErrorCount + categoryErrorCount
+ scriptSummaryFile.Write("<tr>")
+ scriptSummaryFile.Write("<td>")
+ scriptSummaryFile.WriteElement("b", "Category Total")
+ scriptSummaryFile.Write("</td>")
+ scriptSummaryFile.Write("<td>")
+ scriptSummaryFile.WriteElement("center", "<b>"+str(categoryErrorCount)+"</b>")
+ scriptSummaryFile.Write("</td>")
+ scriptSummaryFile.Write("</tr>")
+ scriptSummaryFile.Write("</table>")
+
+ scriptSummaryFile.WriteBreak()
+ scriptSummaryFile.WriteElement("b", "Total: " + str(totalErrorCount))
+ scriptSummaryFile.WriteBreak()
+
+ scriptSummaryFile.Close()
+
+ def WriteScriptReport(self, aHtmlRenderer, aOutputPath, aScript):
+ totalErrorCount = 0
+ scriptReportFile = CHtmlOutputFile(aOutputPath)
+ scriptReportFile.Write("<font face=verdana>")
+ scriptReportFile.WriteElement("h2", "Problem Report")
+ scriptReportFile.WriteElement("h3", "Problem: " + aScript.iTitle)
+ scriptReportFile.Write(aScript.iDescription)
+ scriptReportFile.WriteBreak()
+ scriptReportFile.WriteBreak()
+
+ found = False
+ for component in scanner.iComponentManager.iCompletedComponents:
+ errorCount = scanner.iComponentManager.ScriptComponentErrorCount(component.iFullPath, aScript.iScriptName)
+ if errorCount > 0:
+ found = True
+ break
+
+ if found:
+ scriptReportFile.Write("<table border=\"1\" width=\"100%\">")
+ scriptReportFile.Write("<tr bgcolor=\"#0099ff\">")
+ scriptReportFile.WriteElement("th width=\"80%\"", "Component")
+ scriptReportFile.WriteElement("th", "Items Found")
+ scriptReportFile.Write("</tr>")
+ for component in scanner.iComponentManager.iCompletedComponents:
+ errorCount = scanner.iComponentManager.ScriptComponentErrorCount(component.iFullPath, aScript.iScriptName)
+ if errorCount > 0:
+ scriptReportFile.Write("<tr>")
+ scriptReportFile.Write("<td>")
+ scriptComponentPath = aHtmlRenderer.ScriptComponentPath(component.iFullPath, aScript.iScriptName, "..")
+ scriptReportFile.WriteLink(scriptComponentPath, component.iFullPath)
+ scriptReportFile.Write("</td>")
+ scriptReportFile.Write("<td>")
+ scriptReportFile.WriteElement("center", str(errorCount))
+ scriptReportFile.Write("</td>")
+ scriptReportFile.Write("</tr>")
+ totalErrorCount = totalErrorCount + errorCount
+ scriptReportFile.Write("<tr>")
+ scriptReportFile.Write("<td>")
+ scriptReportFile.WriteElement("b", "Total")
+ scriptReportFile.Write("</td>")
+ scriptReportFile.Write("<td><center>")
+ scriptReportFile.WriteElement("b", str(totalErrorCount))
+ scriptReportFile.Write("</center></td>")
+ scriptReportFile.Write("</tr>")
+ scriptReportFile.Write("</table>")
+ else:
+ scriptReportFile.WriteBreak()
+ scriptReportFile.WriteElement("i", "There are no items of this problem type to report.")
+ scriptReportFile.WriteBreak()
+
+ scriptReportFile.Close()
+ return totalErrorCount
+
+
+class CHtmlScriptComponentFile:
+
+ # #######################################################
+ # CHtmlScriptComponentFile
+ # Encapsulates access to the HTML output files with the greatest amount of detail.
+ # Each of these files is for a specific problem (script) and for a specific component.
+
+ # The file handle is closed between each call to avoid exhausting the system
+ # limit for open file handles. Many of these files may be open at one time,
+ # and the number of open files is dependent on both the directory structure
+ # being traversed and the number of types of problems found.
+
+ def __init__(self, aLxrUrl, aLxrVersion):
+ self.iLxrUrl = aLxrUrl
+ self.iLxrVersion = aLxrVersion
+
+ def BeginOutputFile(self, aOutputPath, aScript, aComponentName):
+ if not os.path.isdir(os.path.dirname(aOutputPath)):
+ os.makedirs(os.path.dirname(aOutputPath))
+ outputFile = file(aOutputPath, "w")
+ self.iScriptComponentFile = CHtmlOutputFileBase()
+ self.iScriptComponentFile.Write(outputFile, "<font face=verdana>")
+ self.iScriptComponentFile.WriteHeader(outputFile)
+ self.iScriptComponentFile.WriteElement(outputFile, "h2", "Detailed Problem Report")
+ self.iScriptComponentFile.WriteElement(outputFile, "h3", "Component: "+aComponentName)
+ self.iScriptComponentFile.WriteElement(outputFile, "h3", "Problem: "+aScript.iTitle)
+ self.iScriptComponentFile.Write(outputFile, aScript.iDescription)
+ self.iScriptComponentFile.WriteBreak(outputFile)
+ self.iScriptComponentFile.Write(outputFile, "<hr>")
+ self.iScriptComponentFile.WriteBreak(outputFile)
+ outputFile.close()
+
+ def ReportError(self, aOutputPath, aLineContext):
+ outputFile = file(aOutputPath, "a")
+ if self.iLxrUrl == None:
+ # Mozilla Firefox cannot open links to local files,
+ # so it is necessary to convert local file path
+ filePath = "file:///" + aLineContext.iFileName
+ else:
+ # generate link to LXR server instead of local file system
+ filePath = self.iLxrUrl + aLineContext.iFileName[len(scanner.iComponentManager.iRootPath):]
+ if self.iLxrVersion <> None:
+ filePath = filePath + "?v="+self.iLxrVersion
+ filePath = filePath + '#%03d'%aLineContext.iLineNumber
+ self.iScriptComponentFile.WriteLink(outputFile, filePath, self.TrimFileName(aLineContext))
+ self.iScriptComponentFile.Write(outputFile, "(" + str(aLineContext.iLineNumber) + ") ")
+ self.iScriptComponentFile.Write(outputFile, aLineContext.iClassName+"::"+aLineContext.iMethodName+" ")
+ self.iScriptComponentFile.Write(outputFile, "<code><font color=red>"+self.CleanUpText(aLineContext.iLineText))
+ self.iScriptComponentFile.Write(outputFile, "</font></code>")
+ self.iScriptComponentFile.WriteBreak(outputFile)
+ if len(scanner.iRendererManager.iAnnotation)>0:
+ self.iScriptComponentFile.Write(outputFile, scanner.iRendererManager.iAnnotation)
+ self.iScriptComponentFile.WriteBreak(outputFile)
+ scanner.iRendererManager.iAnnotation = ""
+ outputFile.close()
+
+ def EndOutputFile(self, aOutputPath):
+ outputFile = file(aOutputPath, "a")
+ self.iScriptComponentFile.WriteFooter(outputFile)
+ outputFile.close()
+
+ def TrimFileName(self, aLineContext):
+ filename = aLineContext.iFileName
+ componentNameLen = len(aLineContext.iComponentName)
+ if len(filename) > componentNameLen:
+ if filename[0:componentNameLen] == aLineContext.iComponentName:
+ filename = filename[componentNameLen:]
+ if filename[0] == os.path.sep:
+ filename = filename[1:]
+ return filename
+
+ def CleanUpText(self, aLineText):
+ # check for sub-strings that look like HTML tags and preform clean up if needed
+ reTag = re.compile(r"""(<.+>)""", re.VERBOSE)
+ foundTag = reTag.search(aLineText)
+ if foundTag:
+ aNewLineText = aLineText.replace("<", "<")
+ aNewLineText = aNewLineText.replace(">", ">")
+ return aNewLineText
+ else:
+ return aLineText
+
+
+def ComponentCompare(a, b):
+ return cmp(os.path.normcase(a.iFullPath), os.path.normcase(b.iFullPath))
+
+
+class CHtmlRenderer(CRendererBase):
+
+ # #######################################################
+ # CHtmlRenderer - a renderer for HTML output
+
+ # I have nothing to offer but blood, toil, tears and sweat.
+ # - Winston Churchill, 1940
+
+ def __init__(self, aRendererManager, aOutputDirectory, aLxrUrl, aLxrVersion):
+ self.RegisterSelf("html", "HTML renderer", aRendererManager)
+ self.iOutputDirectory = aOutputDirectory
+ if os.path.isdir(self.iOutputDirectory) != True :
+ os.makedirs(self.iOutputDirectory)
+ self.iScriptComponentFile = CHtmlScriptComponentFile(aLxrUrl, aLxrVersion)
+ self.iScriptComponentFilePaths = {}
+ print
+ print KVersion
+ print KCopyrightLine1
+ print KCopyrightLine2
+
+ def BeginFile(self, aFilename):
+ self.iFilename = aFilename
+ scanner.ReportAction("Scanning file " + aFilename)
+
+ def ReportError(self, aLineContext, aScript):
+ outputPath = self.ScriptComponentPath(aLineContext.iComponentName, aScript.iScriptName)
+ if not os.path.isfile(outputPath):
+ self.iScriptComponentFilePaths[aLineContext.iComponentName].append(outputPath)
+ self.iScriptComponentFile.BeginOutputFile(outputPath, aScript, aLineContext.iComponentName)
+ self.iScriptComponentFile.ReportError(outputPath, aLineContext)
+
+ def EndFile(self):
+ return
+
+ def BeginComponent(self, aComponent):
+ self.iScriptComponentFilePaths[aComponent.iFullPath] = []
+
+ def EndComponent(self, aComponent):
+ if self.iScriptComponentFilePaths.has_key(aComponent.iFullPath):
+ for outputPath in self.iScriptComponentFilePaths[aComponent.iFullPath]:
+ self.iScriptComponentFile.EndOutputFile(outputPath)
+ del self.iScriptComponentFilePaths[aComponent.iFullPath]
+ relativeComponentName = scanner.iComponentManager.RelativeComponentName(aComponent.iFullPath)
+ if len(relativeComponentName) < 1: # root component - final component
+ scanner.iEndTime = datetime.datetime.now().ctime()
+ scanner.iComponentManager.iCompletedComponents.sort(ComponentCompare)
+ scriptSummaryFiles = CHtmlScriptSummaryFiles()
+ scriptSummaryFiles.CreateSummaries(self, self.iOutputDirectory)
+ componentSummaryFiles = CHtmlComponentSummaryFiles()
+ componentSummaryFiles.CreateSummaries(self, self.iOutputDirectory)
+
+ def ScriptComponentPath(self, aComponentName, aScriptName, aRel=None):
+ componentName = scanner.iComponentManager.ComponentName(aComponentName)
+ if aRel==None:
+ aRel = self.iOutputDirectory
+ outputPath = os.path.normpath(os.path.join(aRel, "byComponent"))
+ outputPath = os.path.normpath(os.path.join(outputPath, componentName))
+ outputPath = os.path.normpath(os.path.join(outputPath, aScriptName+".html"))
+ return outputPath
+
+
+class CRendererManager:
+
+ # #######################################################
+ # CRendererManager
+ # this class handles all the renderers
+
+ def __init__(self):
+ # declare associative list of renderers: iRendererList[name]=renderer
+ self.iRendererList = {}
+ self.iAnnotation = ""
+
+ def AddRenderer(self, aRenderer):
+ self.iRendererList[aRenderer.iName.lower()] = aRenderer
+
+ def PrintListOfRenderers(self):
+ print("Renderers:")
+ for name, renderer in self.iRendererList.items():
+ print("\t" + name + "\t" + renderer.iDescription)
+
+ print("")
+
+ def BeginFile(self, aFilename):
+ for name, renderer in self.iRendererList.items():
+ renderer.BeginFile(aFilename)
+
+ def ReportError(self, aLineContext, aScript):
+ for name, renderer in self.iRendererList.items():
+ renderer.ReportError(aLineContext, aScript)
+
+ def ReportAnnotation(self, aAnnotation):
+ self.iAnnotation = aAnnotation
+
+ def EndFile(self):
+ for name, renderer in self.iRendererList.items():
+ renderer.EndFile()
+
+ def BeginComponent(self, aComponent):
+ for name, renderer in self.iRendererList.items():
+ renderer.BeginComponent(aComponent)
+
+ def EndComponent(self, aComponent):
+ for name, renderer in self.iRendererList.items():
+ renderer.EndComponent(aComponent)
+
+
+class CComponent:
+
+ # #######################################################
+ # CComponent - a single component, identified by the
+ # directory path to its source code
+
+ def __init__(self, aPath):
+ self.iFullPath = aPath
+ self.iScriptErrorCounts = {}
+ self.iHasGroupDir = False
+ self.iNumberOfLinesScanned = 0
+
+ def appendComponent(self, aComponent):
+ for scriptName in aComponent.iScriptErrorCounts.keys():
+ if self.iScriptErrorCounts.has_key(scriptName):
+ self.iScriptErrorCounts[scriptName] += aComponent.iScriptErrorCounts[scriptName]
+ else:
+ self.iScriptErrorCounts[scriptName] = aComponent.iScriptErrorCounts[scriptName]
+ self.iNumberOfLinesScanned += aComponent.iNumberOfLinesScanned
+ return
+
+
+class CComponentManager:
+
+ # #######################################################
+ # CComponentManager - controls access to components
+
+ def __init__(self):
+ self.iComponentStack = []
+ self.iCompletedComponents = []
+ self.iRootComponent = CComponent("")
+ self.iUseFullComponentPath = False
+
+ def SetRoot(self, aRootPath):
+ # set the list of root directories - used to left-trim component names
+ self.iRootPath = self.SanitizePath(aRootPath)
+
+ def BeginDirectory(self, aPath):
+ aPath = self.SanitizePath(aPath)
+ if os.path.isdir(aPath):
+ newComponent = CComponent(aPath)
+ contents = os.listdir(aPath)
+ for entry in contents:
+ if (entry.upper() == "GROUP"):
+ entryPath = os.path.normpath(os.path.join(aPath, entry))
+ if os.path.isdir(entryPath):
+ newComponent.iHasGroupDir = True
+ break
+ if len(self.iComponentStack) > 0:
+ topComponent = self.iComponentStack[len(self.iComponentStack)-1]
+ if (newComponent.iHasGroupDir or (not topComponent.iHasGroupDir)):
+ self.BeginComponent(newComponent)
+ else:
+ scanner.iLog.Write(aPath + " taken as part of " + topComponent.iFullPath)
+ else:
+ self.BeginComponent(newComponent)
+ else:
+ scanner.iLog.Write("ERROR: CComponentManager::BeginDirectory: bad path "+aPath)
+ return aPath
+
+ def EndDirectory(self, aPath, numberOfLinesScanned):
+ aPath = self.SanitizePath(aPath)
+ if len(self.iComponentStack) > 0:
+ topComponent = self.iComponentStack[len(self.iComponentStack)-1]
+ topComponent.iNumberOfLinesScanned += numberOfLinesScanned
+ if (topComponent.iFullPath == aPath):
+ self.EndComponent()
+
+ def ReportError(self, aLineContext, aScript):
+ scanner.iRendererManager.ReportError(aLineContext, aScript)
+ for component in self.iComponentStack:
+ if component.iFullPath == aLineContext.iComponentName:
+ if component.iScriptErrorCounts.has_key(aScript.iScriptName):
+ component.iScriptErrorCounts[aScript.iScriptName] = component.iScriptErrorCounts[aScript.iScriptName] + 1
+ else:
+ component.iScriptErrorCounts[aScript.iScriptName] = 1
+
+ def ScriptComponentErrorCount(self, aComponentName, aScriptName):
+ for component in self.iCompletedComponents:
+ if component.iFullPath == aComponentName:
+ if component.iScriptErrorCounts.has_key(aScriptName):
+ return component.iScriptErrorCounts[aScriptName]
+ else:
+ return 0
+ return 0
+
+ def BeginComponent(self, aComponent):
+ scanner.iRendererManager.BeginComponent(aComponent)
+ scanner.ReportAction("Begin component: " + aComponent.iFullPath)
+ self.iComponentStack.append(aComponent)
+
+ def EndComponent(self):
+ previousComponent = self.iComponentStack.pop()
+ matchingComponent = self.MatchingComponent(previousComponent)
+ if (matchingComponent <> None):
+ matchingComponent.appendComponent(previousComponent)
+ else:
+ self.iCompletedComponents.append(previousComponent)
+ scanner.ReportAction("End component: " + previousComponent.iFullPath)
+ scanner.iRendererManager.EndComponent(previousComponent)
+
+ def MatchingComponent(self, aComponent):
+ for component in self.iCompletedComponents:
+ if (ComponentCompare(component, aComponent) == 0):
+ return component
+ return None
+
+ def CurrentComponentName(self):
+ if len(self.iComponentStack) < 1:
+ return None
+ return self.iComponentStack[len(self.iComponentStack)-1].iFullPath
+
+ def SanitizePath(self, aPath):
+ # Translate an unspecified or relative pathname into an absolute pathname
+ if len(aPath) < 1:
+ aPath = "."
+ aPath = os.path.normpath(aPath)
+ # translate "." and ".." into absolute paths
+ aPath = os.path.abspath(aPath)
+ return aPath
+
+ def ComponentName(self, aFullComponentName):
+ if (self.iUseFullComponentPath):
+ (unused, componentName) = os.path.splitdrive(aFullComponentName)
+ if len(componentName) > 0:
+ if componentName[0] == os.path.sep and len(componentName) > 1:
+ componentName = componentName[1:]
+ return componentName
+ else:
+ return self.RelativeComponentName(aFullComponentName)
+
+ def RelativeComponentName(self, aFullComponentName):
+ # Remove the root path from the specified component name
+ rootLen = len(self.iRootPath)
+ if aFullComponentName[0:rootLen] == self.iRootPath:
+ relativeComponentName = aFullComponentName[rootLen:]
+ else:
+ # this case is unexpected...but we'll try to make the best of it
+ (unused, relativeComponentName) = os.path.splitdrive(aFullComponentName)
+ # trim leading path separator, if present
+ if len(relativeComponentName) > 0:
+ if relativeComponentName[0] == os.path.sep and len(relativeComponentName) > 1:
+ relativeComponentName = relativeComponentName[1:]
+ return relativeComponentName
+
+
+class CLineContext:
+
+ # #######################################################
+ # CLineContext
+ # A description of the line of source code currently being scanned
+
+ iComponentName = ""
+ iFileName = ""
+ iLineNumber = 0
+ iClassName = ""
+ iMethodName = ""
+ iLineText = ""
+
+
+class CCodeScanner:
+
+ # #######################################################
+ # CCodeScanner - main application class
+
+ def __init__(self):
+ self.iCategoriedScripts = CCategorisedScripts()
+ self.iRendererManager = CRendererManager()
+ self.iComponentManager = CComponentManager()
+ self.iLineContext = CLineContext()
+ self.iDomConfig = None
+ self.iVerbose = False
+ self.iLog = None
+ self.iSource = None
+ self.iEncodedFileList = None
+ self.iOutputDirectory = None
+ self.iStartTimeObj = None
+ self.iStartTime = None
+ self.iEndTime = None
+ self.iLxrUrl = None
+ self.iLxrVersion = None
+ self.iConfigFilename = ""
+ self.iInputFilenames = ""
+ self.iLogFilename = ""
+ self.iOutputFormat = ""
+ self.iTimeStampedOutput = ""
+ self.iReMethod = re.compile(r"""
+ ((?P<class>\w+)::~?)?
+ (?P<method>[A-Za-z0-9<>=!*\-+/]+)
+ [\s\n]*
+ \(
+ [^;]*
+ $
+ """, re.VERBOSE)
+
+ def ReportError(self, aErrorMsg):
+ self.iLog.Write(aErrorMsg)
+ print aErrorMsg
+
+ def ReportAction(self, aAction):
+ self.iLog.Write(aAction)
+ if self.iVerbose:
+ print aAction
+
+ def ReportInfo(self, aInfoMsg):
+ self.iLog.Write(aInfoMsg)
+ print aInfoMsg
+
+ def CleanOutputDirectory(self):
+ self.iLog.Write("Deleting existing contents of output directory " + self.iOutputDirectory)
+ for root, dirs, files in os.walk(self.iOutputDirectory, topdown = False):
+ for name in files:
+ os.remove(os.path.join(root, name))
+ for name in dirs:
+ os.rmdir(os.path.join(root, name))
+
+ def CheckSourceIncluded(self, aSourceFileName):
+ if (self.iDomConfig <> None):
+ for sourceNode in self.iDomConfig.getElementsByTagName("sources"):
+ for excludeSourceNode in sourceNode.getElementsByTagName("exclude"):
+ reExcludeSourceStr = excludeSourceNode.firstChild.nodeValue
+ reExcludeSource = re.compile(reExcludeSourceStr, re.IGNORECASE)
+ if reExcludeSource.search(aSourceFileName):
+ self.ReportInfo("Note: excluding " + aSourceFileName + " : " + reExcludeSourceStr)
+ return False
+ return True
+
+ def CheckScriptEnabled(self, aScript):
+ if (self.iDomConfig <> None):
+ for scriptsNode in self.iDomConfig.getElementsByTagName("scripts"):
+ for scriptNode in scriptsNode.getElementsByTagName(aScript.iScriptName):
+ enabledAttr = scriptNode.getAttribute("enable")
+ if (enabledAttr.lower() == "false"):
+ return False
+ for severitiesNode in self.iDomConfig.getElementsByTagName("severities"):
+ for severityNode in severitiesNode.getElementsByTagName(KSeverityConfigMap[aScript.iSeverity]):
+ enabledAttr = severityNode.getAttribute("enable")
+ if (enabledAttr.lower() == "false"):
+ return False
+ for categoriesNode in self.iDomConfig.getElementsByTagName("categories"):
+ for categoryNode in categoriesNode.getElementsByTagName(KCategoryConfigMap[aScript.iCategory]):
+ enabledAttr = categoryNode.getAttribute("enable")
+ if (enabledAttr.lower() == "false"):
+ return False
+ return True
+
+ def UpdateScriptCategory(self, aScript):
+ if (self.iDomConfig <> None):
+ for scriptsNode in self.iDomConfig.getElementsByTagName("scripts"):
+ for scriptNode in scriptsNode.getElementsByTagName(aScript.iScriptName):
+ if scriptNode.hasAttribute("category"):
+ newCategory = scriptNode.getAttribute("category").lower()
+ if (newCategory <> KCategoryConfigMap[aScript.iCategory]):
+ for name, value in KCategoryConfigMap.items():
+ if (newCategory == value):
+ return name
+ # no update needed, return original category
+ return aScript.iCategory
+
+ def UpdateScriptSeverity(self, aScript):
+ if (self.iDomConfig <> None):
+ for scriptsNode in self.iDomConfig.getElementsByTagName("scripts"):
+ for scriptNode in scriptsNode.getElementsByTagName(aScript.iScriptName):
+ if scriptNode.hasAttribute("severity"):
+ newSeverity = scriptNode.getAttribute("severity").lower()
+ if (newSeverity <> KSeverityConfigMap[aScript.iSeverity]):
+ for name, value in KSeverityConfigMap.items():
+ if (newSeverity == value):
+ return name
+ # no update needed, return original severity
+ return aScript.iSeverity
+
+ def ScanFile(self, aSourceFile):
+ self.iLineContext.iFileName = aSourceFile
+ self.iLineContext.iLineNumber = 0
+ self.iLineContext.iClassName = ""
+ self.iLineContext.iMethodName = ""
+ self.iLineContext.iComponentName = self.iComponentManager.CurrentComponentName()
+
+ self.iRendererManager.BeginFile(aSourceFile)
+
+ # note source file extension - used for filtering later on
+ (unused, sourceFileExt) = os.path.splitext(aSourceFile)
+ if len(sourceFileExt) > 0 and sourceFileExt[0] == '.':
+ sourceFileExt = sourceFileExt[1:]
+
+ # open, read, and preparse source file
+ inputFileHandle = file(aSourceFile, "r")
+ inputFileLines = inputFileHandle.readlines()
+ inputFileHandle.close()
+
+ (noQuoteFileLines, noCommentFileLines, noCommentOrQuoteFileLines, csCommands) = self.PreParseSourceFile(inputFileLines)
+
+ # bundle all the filtered versions of the file contents into
+ # a hash to re-factor code
+ fileContentsToTest = { KIgnoreNothing : inputFileLines,
+ KIgnoreComments : noCommentFileLines,
+ KIgnoreQuotes : noQuoteFileLines,
+ KIgnoreCommentsAndQuotes : noCommentOrQuoteFileLines
+ }
+
+ # now apply test scripts to source file
+ iBraceCount = 0
+ iBraceCountList = []
+ newCurrentClassName = ""
+ newCurrentMethodName = ""
+ self.iCurrentClassName = ""
+ self.iCurrentMethodName = ""
+ self.iCurrentMethodStart = -1
+
+ totalNumberOfLines = len(inputFileLines)
+ reConstant = re.compile(r"""
+ ^\s*
+ (static\s+)?
+ const
+ \s+
+ \w+ # type
+ \s*
+ [\*&]? # reference or pointer
+ \s*
+ \w+ # name
+ \s*
+ (=|\()
+ """, re.VERBOSE)
+ reInheritance = re.compile("[\s:]*(public|protected|private)\s*([\w:]+)")
+ rePreprocessorIf = re.compile("^\s*\#(el)*if(.*)")
+ rePreprocessorElse = re.compile("^\s*\#else")
+ rePreprocessorEnd = re.compile("^\s*\#endif")
+ reTypedef = re.compile("^\s*typedef")
+ i = 0
+ while (i < totalNumberOfLines):
+ # for extra open braces in #if blocks
+ if (rePreprocessorIf.search(noCommentOrQuoteFileLines[i])):
+ iBraceCountList.append(iBraceCount)
+ if (rePreprocessorElse.search(noCommentOrQuoteFileLines[i])):
+ if (len(iBraceCountList) > 0):
+ iBraceCount = iBraceCountList.pop()
+ if (rePreprocessorEnd.search(noCommentOrQuoteFileLines[i])):
+ if (len(iBraceCountList) > 0):
+ iBraceCountList.pop()
+
+ if (newCurrentMethodName == ""):
+ methodString = noCommentOrQuoteFileLines[i]
+ currentLine = i
+ m = self.iReMethod.search(methodString)
+ if not m and (i + 1 < totalNumberOfLines):
+ currentLine = i + 1
+ methodString += noCommentOrQuoteFileLines[currentLine]
+ m = self.iReMethod.search(methodString)
+
+ if m and (iBraceCount == 0) and (methodString.find("#") == -1) and (methodString.find("_LIT") == -1): # must be at root level and not a preprocessor directive or a _LIT
+ if not reTypedef.match(methodString) and not reConstant.match(methodString): # must not be typedef or constant declaration
+ # check for cases where macros are used to declare a class
+ # by searching for the inheritance part
+ # eg. NONSHARABLE_CLASS(CMyClass) : public CBase
+ isClass = reInheritance.search(methodString)
+ if not isClass and (currentLine + 1 < totalNumberOfLines):
+ methodString += noCommentOrQuoteFileLines[currentLine + 1]
+ isClass = reInheritance.search(methodString)
+ if not isClass:
+ newCurrentMethodName = m.group('method')
+ if m.group('class'):
+ newCurrentClassName = m.group('class')
+ else:
+ newCurrentClassName = ""
+
+ iBraceCount += noCommentOrQuoteFileLines[i].count("{")
+ if (iBraceCount > 0) and (newCurrentMethodName <> ""):
+ self.iCurrentClassName = newCurrentClassName
+ self.iCurrentMethodName = newCurrentMethodName
+ self.iCurrentMethodStart = i
+ newCurrentClassName = ""
+ newCurrentMethodName = ""
+
+ self.iLineContext.iLineNumber = i+1
+ self.iLineContext.iClassName = self.iCurrentClassName
+ self.iLineContext.iMethodName = self.iCurrentMethodName
+
+ # perform all test scripts onto source file
+ for script in self.iCategoriedScripts.AllScripts():
+ if (script.iFileExts.count(sourceFileExt) > 0
+ and fileContentsToTest[script.iIgnore][i] != "\n"
+ and script.iCompare(fileContentsToTest[script.iIgnore], i, script.iReMatch, aSourceFile)):
+ # skip any script that has been disabled via CodeScanner command(s) in sources
+ if script.iScriptName.lower() in csCommands[i].lower():
+ continue
+ self.iLineContext.iLineText = fileContentsToTest[script.iIgnore][i]
+ self.iComponentManager.ReportError(self.iLineContext, script)
+
+ iBraceCount -= noCommentOrQuoteFileLines[i].count("}")
+ if (iBraceCount < 0): # for extra close braces in #if blocks
+ iBraceCount = 0
+
+ if (iBraceCount == 0):
+ self.iCurrentClassName = ""
+ self.iCurrentMethodName = ""
+ self.iCurrentMethodStart = -1
+
+ i = i + 1
+
+ self.iRendererManager.EndFile()
+ return totalNumberOfLines
+
+ def TraverseDirectory(self, aDirectory):
+ # skip folders marked to be excluded in configuration file
+ aPath = self.iComponentManager.SanitizePath(aDirectory)
+ if (not self.CheckSourceIncluded(aPath)) or (not self.CheckSourceIncluded(aPath + os.path.sep)):
+ return
+ aDirectory = self.iComponentManager.BeginDirectory(aDirectory)
+ contents = os.listdir(aDirectory)
+ numberOfLinesScanned = 0
+ for entry in contents:
+ entryPath = os.path.normpath(os.path.join(aDirectory, entry))
+ if os.path.isdir(entryPath):
+ self.TraverseDirectory(entryPath)
+ else:
+ if self.CheckSourceIncluded(entryPath):
+ numberOfLinesScanned += self.ScanFile(entryPath)
+ self.iComponentManager.EndDirectory(aDirectory, numberOfLinesScanned)
+
+ def AddScript(self, aScript):
+ enabled = self.CheckScriptEnabled(script)
+ if enabled:
+ aScript.iCategory = self.UpdateScriptCategory(aScript)
+ aScript.iSeverity = self.UpdateScriptSeverity(aScript)
+ self.iCategoriedScripts.AddScript(aScript)
+ else:
+ self.ReportInfo("Note: script '" + aScript.iScriptName + "' DISABLED")
+
+ def AddCustomScript(self, aScript):
+ self.ReportInfo("Note: custom rule '" + aScript.iScriptName + "' ADDED")
+ self.iCategoriedScripts.AddScript(aScript)
+
+ def PreParseSourceFile(self, aLines):
+ # it provides 3 versions of input:
+ # 1. without quotes
+ # 2. without comments
+ # 3. without quotes and without comments
+
+ inCommentBlock = 0
+ noQuoteLines = []
+ noCommentLines = []
+ noCommentOrQuoteLines = []
+ csCommands = []
+ reCSCommand = re.compile("codescanner((::\w+)+)") # CodeScanner command(s) in comments
+
+ for line in aLines:
+ noQuoteLine = ""
+ noCommentLine = ""
+ noCommentOrQuoteLine = ""
+ csCommand = "\n"
+
+ i = 0
+ startQuote = 0
+ b = 0
+ escCount = 0
+
+ while i < len(line):
+ # skip quotes
+ if not inCommentBlock and ((line[i] == "\"") or (line[i] == "\'")):
+ startQuote = i
+ i += 1
+ while (i < len(line)):
+ endIndex = line[i:].find(line[startQuote])
+ if (endIndex <> -1):
+ b = i + endIndex - 1
+ escCount = 0
+ while (line[b] == "\\"):
+ escCount += 1
+ b -= 1
+
+ i += endIndex + 1
+ if (escCount % 2 == 0):
+ noQuoteLine += "\"\""
+ noCommentOrQuoteLine += "\"\""
+ noCommentLine += line[startQuote:i]
+ break
+ else:
+ # print "Unterminated quote : " + line
+ break
+ continue
+
+ # parse comments
+ if not inCommentBlock:
+ if (line[i] == "/"):
+ if (i < (len(line)-1)):
+ if (line[i + 1] == "/"):
+ noCommentLine += "\n"
+ noCommentOrQuoteLine += "\n"
+ noQuoteLine += line[i:]
+ # look for CodeScanner command(s) in comments
+ m = reCSCommand.search(line[i:])
+ if m:
+ csCommand = m.group(1)
+ break
+ elif (line[i + 1] == "*"):
+ inCommentBlock = 1
+ i += 2
+ noQuoteLine += "/*"
+ continue
+
+ noCommentLine += line[i]
+ noCommentOrQuoteLine += line[i]
+ noQuoteLine += line[i]
+ else:
+ # look for CodeScanner command(s) in comments
+ m = reCSCommand.search(line[i:])
+ if m:
+ csCommand = m.group(1)
+ endIndex = line[i:].find("*/")
+ if (endIndex <> -1):
+ inCommentBlock = 0
+ noQuoteLine += line[i:i + endIndex + 2]
+ i += endIndex + 2
+ continue
+ else:
+ noCommentLine += "\n"
+ noCommentOrQuoteLine += "\n"
+ noQuoteLine = line[i:]
+ break
+
+ i += 1
+
+ noCommentLines.append(noCommentLine)
+ noCommentOrQuoteLines.append(noCommentOrQuoteLine)
+ noQuoteLines.append(noQuoteLine)
+ csCommands.append(csCommand)
+
+ return [noQuoteLines, noCommentLines, noCommentOrQuoteLines, csCommands]
+
+ def ReadConfigFile(self):
+ if self.iConfigFilename <> "":
+ if (os.path.isfile(self.iConfigFilename)):
+ self.iDomConfig = xml.dom.minidom.parse(self.iConfigFilename)
+ if self.iVerbose:
+ print "Note: using configuration file " + self.iConfigFilename
+ else:
+ self.ReportInfo("Unable to open specified configuration file: " + self.iConfigFilename)
+ self.iLog.Close()
+ sys.exit(2)
+
+ def ReadArgumentsFromConfigFile(self):
+ if (self.iDomConfig <> None):
+ for argumentsNode in self.iDomConfig.getElementsByTagName("arguments"):
+ # read input file names
+ for inputFileNode in argumentsNode.getElementsByTagName("input"):
+ self.iInputFilenames += inputFileNode.firstChild.nodeValue + "::"
+ # read output format
+ for outputFormatNode in argumentsNode.getElementsByTagName("outputformat"):
+ self.iOutputFormat += outputFormatNode.firstChild.nodeValue
+ # read lxr URL
+ for lxrURLNode in argumentsNode.getElementsByTagName("lxr"):
+ self.iLxrUrl = lxrURLNode.firstChild.nodeValue
+ # read lxr version
+ for lxrVersionNode in argumentsNode.getElementsByTagName("lxrversion"):
+ self.iLxrVersion = lxrVersionNode.firstChild.nodeValue
+ # read time stamped output option
+ for timeStampedOutputNode in argumentsNode.getElementsByTagName("timestampedoutput"):
+ self.iTimeStampedOutput = timeStampedOutputNode.firstChild.nodeValue
+
+ def ReadCustomRulesFromConfigFile(self):
+ if (self.iDomConfig <> None):
+ for customRulesNode in self.iDomConfig.getElementsByTagName("customrules"):
+ for customRuleNode in customRulesNode.getElementsByTagName("customrule"):
+ ignoreComments = True
+
+ # read the name of the rule
+ ruleName = ""
+ for ruleNameNode in customRuleNode.getElementsByTagName("name"):
+ if (ruleNameNode == None) or (ruleNameNode.firstChild == None) or (ruleNameNode.firstChild.nodeValue == None):
+ continue
+ else:
+ ruleName = ruleNameNode.firstChild.nodeValue
+ if len(ruleName) == 0:
+ self.ReportError("Missing custom rule name in configuration file: " + self.iConfigFilename)
+ continue
+
+ # read the keywords associated with the rule
+ keywordList = []
+ badKeywordElement = False
+ for keywordNode in customRuleNode.getElementsByTagName("keyword"):
+ # read keyword content
+ if (keywordNode == None) or (keywordNode.firstChild == None) or (keywordNode.firstChild.nodeValue == None):
+ badKeywordElement = True
+ continue
+ newKeyword = CCustomRuleKeyword()
+ newKeyword.iContent = keywordNode.firstChild.nodeValue
+
+ # read keyword type
+ if not keywordNode.hasAttribute("type"):
+ badKeywordElement = True
+ continue
+ type = keywordNode.getAttribute("type").lower()
+ if type in KCustomRuleKeywordMap.values():
+ if type == KKeywordComment:
+ ignoreComments = False
+ else:
+ type = KCustomRuleKeywordMap[KKeywordUnknown]
+ newKeyword.iType = type
+ keywordList.append(newKeyword)
+ if (len(keywordList) == 0) or (badKeywordElement == True):
+ self.ReportBadCustomRuleElement(ruleName, "keyword")
+ continue
+
+ # read the file types associated with the rule
+ fileTypeList = []
+ badFileTypeElement = False
+ for fileTypeNode in customRuleNode.getElementsByTagName("filetype"):
+ if (fileTypeNode == None) or (fileTypeNode.firstChild == None) or (fileTypeNode.firstChild.nodeValue == None):
+ badFileTypeElement = True
+ continue
+ newFileType = fileTypeNode.firstChild.nodeValue
+ fileTypeList.append(newFileType.lower())
+ if (len(fileTypeList) == 0) or (badFileTypeElement == True):
+ self.ReportBadCustomRuleElement(ruleName, "file type")
+ continue
+
+ # read the severity level of the rule
+ severity = KSeverityLow
+ for severityNode in customRuleNode.getElementsByTagName("severity"):
+ if (severityNode == None) or (severityNode.firstChild == None) or (severityNode.firstChild.nodeValue == None):
+ self.ReportBadCustomRuleElement(ruleName, "severity")
+ continue
+ severityValue = severityNode.firstChild.nodeValue
+ for severityKey in KSeverityConfigMap.keys():
+ if severityValue == KSeverityConfigMap[severityKey]:
+ severity = severityKey
+
+ # read the tile of the rule
+ title = ""
+ for titleNode in customRuleNode.getElementsByTagName("title"):
+ if (titleNode == None) or (titleNode.firstChild == None) or (titleNode.firstChild.nodeValue == None):
+ continue
+ title = titleNode.firstChild.nodeValue
+ if len(title) == 0:
+ self.ReportBadCustomRuleElement(ruleName, "title")
+ continue
+
+ # read the description of the rule
+ description = ""
+ for descriptionNode in customRuleNode.getElementsByTagName("description"):
+ if (descriptionNode == None) or (descriptionNode.firstChild == None) or (descriptionNode.firstChild.nodeValue == None):
+ continue
+ description = descriptionNode.firstChild.nodeValue
+ if len(description) == 0:
+ self.ReportBadCustomRuleElement(ruleName, "description")
+ continue
+
+ # read the optional link of the rule
+ link = None
+ for linkNode in customRuleNode.getElementsByTagName("link"):
+ if (linkNode == None) or (linkNode.firstChild == None) or (linkNode.firstChild.nodeValue == None):
+ self.ReportBadCustomRuleElement(ruleName, "link")
+ continue
+ link = linkNode.firstChild.nodeValue
+
+ # create the RE string for the custom rule
+ keywordMap = self.ConstructCustomRuleKeywordMap(keywordList)
+ reString = self.ConstructCustomRuleREString(keywordMap)
+ if len(reString) == 0:
+ continue
+
+ # create a script based on the custom rule
+ aScript = CCustomScript(ruleName)
+ aScript.iReString = reString
+ aScript.iReMatch = re.compile(reString)
+ aScript.iFileExts = fileTypeList
+ aScript.iCategory = KCategoryOther
+ if keywordMap.has_key(KKeywordBaseClass):
+ aScript.iBaseClass = keywordMap[KKeywordBaseClass]
+ aScript.iCompare = aScript.DefaultInheritanceCompare
+ if ignoreComments:
+ aScript.iIgnore = KIgnoreComments
+ else:
+ aScript.iIgnore = KIgnoreQuotes
+ aScript.iSeverity = severity
+ aScript.iTitle = title
+ aScript.iIdeTitle = title
+ aScript.iDescription = description
+ if link <> None:
+ aScript.iLink = link
+ self.AddCustomScript(aScript)
+ return
+
+ def ReportBadCustomRuleElement(self, name, element):
+ self.ReportError("<customrule> element '" + name + "' has bad <" + element + "> child element in configuration file: " + self.iConfigFilename)
+
+ def ConstructCustomRuleKeywordMap(self, keywordList):
+ reString = ""
+ keywordMap = {}
+ for keyword in keywordList:
+ if keywordMap.has_key(keyword.iType):
+ keywordMap[keyword.iType] = keywordMap[keyword.iType] + "|" + keyword.iContent
+ else:
+ keywordMap[keyword.iType] = keyword.iContent
+ return keywordMap
+
+ def ConstructCustomRuleREString(self, keywordMap):
+ # generate RE string based on the keyword types
+ if keywordMap.has_key(KKeywordBaseClass):
+ reString = "^\s*class\s+(\w+::)?(\w+)\s*:(.*)"
+ elif keywordMap.has_key(KKeywordCall):
+ reString = "(" + keywordMap[KKeywordCall] + ")\s*\(.*\)\s*;"
+ elif keywordMap.has_key(KKeywordClassName):
+ if keywordMap.has_key(KKeywordMethod):
+ reString = "([A-Za-z0-9]+\s+" + keywordMap[KKeywordClassName] + "::)?(" + keywordMap[KKeywordMethod] + ")\s*\(.*\)\s*[^;]"
+ else:
+ reString = "^\s*class\s+(\w+::)?(" + keywordMap[KKeywordClassName] + ")"
+ elif keywordMap.has_key(KKeywordComment):
+ reString = "/(/|\*).*(" + keywordMap[KKeywordComment] + ")"
+ elif keywordMap.has_key(KKeywordGeneric):
+ reString = "(" + keywordMap[KKeywordGeneric] + ")"
+ elif keywordMap.has_key(KKeywordLocal):
+ reString = "^\s*[A-Z]\w*\s*[\*&\s]\s*(" + keywordMap[KKeywordLocal] + ")\w*\s*[;\(=]"
+ elif keywordMap.has_key(KKeywordMacro):
+ reString = "^\s*\#define\s+(" + keywordMap[KKeywordMacro] + ")"
+ elif keywordMap.has_key(KKeywordMember):
+ reString = "^\s*[A-Z]\w*\s*[\*&\s]\s*(" + keywordMap[KKeywordMember] + ")\w*\s*[;\(=]"
+ elif keywordMap.has_key(KKeywordMethod):
+ reString = "[A-Za-z0-9]+\s+[C|T|R][A-Za-z0-9]+::(" + keywordMap[KKeywordMethod] + ")\s*\(.*\)\s*[^;]"
+ elif keywordMap.has_key(KKeywordParameter):
+ reString = "({)*\s*(" + keywordMap[KKeywordParameter] + ")\s*=\s*(.*);"
+ return reString
+
+
+class CCustomRuleKeyword:
+ # #######################################################
+ # CCustomRuleKeyword - keyword associated with custom rules
+
+ def __init__(self):
+ iContent = ""
+ iType = "unknown"
+
+
+# #######################################################
+
+class CEncodedFile:
+ def Extract(self, aBaseDirectory):
+ outputFileHandle = open(os.path.join(aBaseDirectory, self.iFilename), 'wb')
+ outputFileBinary = zlib.decompress(base64.decodestring(self.iFileBody))
+ outputFileHandle.write(outputFileBinary)
+ outputFileHandle.close()
+
+ iFilename = ""
+ iFileBody = ""
+
+# #######################################################
+
+
+class CEncodedFileList:
+ def AddEncodedFile(self, aEncodedFile):
+ self.iEncodedFileList[aEncodedFile.iFilename.lower()] = aEncodedFile
+
+ def ExtractEncodedFile(self, aFilename, aBaseDirectory):
+ # look for the filename in our list of files
+ filename = aFilename.lower()
+ if (self.iEncodedFileList.has_key(filename)):
+ self.iEncodedFileList[filename].Extract(aBaseDirectory)
+ else:
+ scanner.iLog.Write("Missing "+filename)
+
+ def ExtractAllEncodedFiles(self, aBaseDirectory):
+ # run through associative array and extract everything
+ for filename in self.iEncodedFileList.keys():
+ self.ExtractEncodedFile(filename, aBaseDirectory)
+
+ # declare iEncodedFileList is an associative array
+ iEncodedFileList = {}
+
+
+# #######################################################
+# main()
+scanner = CCodeScanner()
+
+# process command line arguments
+opts, args = getopt.getopt(sys.argv[1:], "hvc:i:l:o:x:r:t:", ["help", "verbose", "config=", "input=", "logfile=", "outputformat=", "lxr=", "lxrversion=", "timestampedoutput="])
+for o, a in opts:
+ if o in ("-h", "--help"):
+ Usage(0)
+ if o in ("-v", "--verbose"):
+ scanner.iVerbose = True
+ if o in ("-c", "--config"):
+ scanner.iConfigFilename = a
+ if o in ("-i", "--input"):
+ scanner.iInputFilenames += a + "::"
+ if o in ("-l", "--logfile"):
+ scanner.iLogFilename = a
+ if o in ("-o", "--outputformat"):
+ scanner.iOutputFormat += a
+ if o in ("-x", "--lxr"):
+ scanner.iLxrUrl = a
+ if o in ("-r", "--lxrversion"):
+ scanner.iLxrVersion = a
+ if o in ("-t", "--timestampedoutput"):
+ scanner.iTimeStampedOutput = a
+
+if len(args) < 1:
+ Usage(1)
+
+scanner.iLog = CLogger(scanner.iLogFilename)
+scanner.iLog.Write("Command line: " + str(sys.argv[1:]))
+scanner.iLog.Write("Current working directory: " + os.getcwd())
+
+scanner.ReadConfigFile()
+scanner.ReadArgumentsFromConfigFile()
+scanner.ReadCustomRulesFromConfigFile()
+
+scanner.iSource = args[0]
+scanner.iEncodedFileList = CEncodedFileList()
+scanner.iStartTimeObj = datetime.datetime.now()
+scanner.iStartTime = scanner.iStartTimeObj.ctime()
+scanner.iOutputDirectory = scanner.iStartTimeObj.strftime("%a-%b-%d-%H-%M-%S-%Y")
+
+# invoke the pysco module to improve performance
+psyco.full()
+
+# choose renderer based on command line arguments
+if len(args) > 1:
+ if ("off" in scanner.iTimeStampedOutput.lower()):
+ scanner.iOutputDirectory = args[1]
+ else:
+ scanner.iOutputDirectory = os.path.normpath(os.path.join(args[1], scanner.iOutputDirectory))
+ scanner.CleanOutputDirectory()
+ if scanner.iOutputFormat <> "":
+ #user specified output format
+ if ("xml" in scanner.iOutputFormat.lower()):
+ CXmlRenderer(scanner.iRendererManager, scanner.iOutputDirectory)
+ if ("html" in scanner.iOutputFormat.lower()):
+ CHtmlRenderer(scanner.iRendererManager, scanner.iOutputDirectory, scanner.iLxrUrl, scanner.iLxrVersion)
+ if ("std" in scanner.iOutputFormat.lower()):
+ CStdOutRenderer(scanner.iRendererManager)
+ else:
+ #default output format
+ CHtmlRenderer(scanner.iRendererManager, scanner.iOutputDirectory, scanner.iLxrUrl, scanner.iLxrVersion)
+else:
+ CStdOutRenderer(scanner.iRendererManager)
+
+#!PARSE
+
+if (scanner.iVerbose):
+ scanner.iCategoriedScripts.PrintListOfTestScripts()
+ scanner.iRendererManager.PrintListOfRenderers()
+
+print
+print "Scanning inititated : " + scanner.iStartTime
+
+if scanner.iInputFilenames <> "":
+ scanner.iComponentManager.iUseFullComponentPath = True
+ #additional input files
+ inputFiles = scanner.iInputFilenames.split("::")
+ for inputFile in inputFiles:
+ if inputFile <> "":
+ ScanDirOrFile(inputFile)
+
+argument = args[0]
+ScanDirOrFile(argument)
+
+print "Scanning finished : " + scanner.iEndTime
+scanner.iLog.Close()
+
+if (scanner.iDomConfig <> None):
+ scanner.iDomConfig.unlink()
+
+sys.exit(0)