1#
2# Copyright 2009, Alexandre Deckner, alex@zappotek.com
3# Distributed under the terms of the MIT License.
4#
5import re, sys, os
6from utils import *
7
8
9def processMatches(matches, name, text, highlights):
10    for match in matches:
11        printMatch(name, match, text)
12        highlights.append((match.start(), match.end(), name))
13
14
15def run(fileSet, rules, outputFileName):
16    openHtml(fileSet, outputFileName)
17
18    for fileName in fileSet:
19        print "\nChecking " + fileName + ":"
20        file = open(fileName, 'r')
21        text = file.read()
22
23        highlights = []
24
25        for name, regexp in rules.items():
26            processMatches(regexp.finditer(text), name, text, highlights)
27
28        highlights.sort()
29        highlights = checkHighlights(highlights)
30
31        file.close()
32
33        renderHtml(text, highlights, fileName, outputFileName)
34
35    closeHtml(outputFileName)
36
37
38def visit(result, dir, names):
39    extensions = [".cpp", ".h"]
40    names.remove(".svn")
41    for name in names:
42        path = os.path.join(dir, name)
43        if os.path.isfile(path) and os.path.splitext(name)[1] in extensions:
44            print "adding", path
45            result.append(path)
46
47
48cppRules = {}
49cppRules["Line over 80 char"] = re.compile('[^\n]{81,}')
50cppRules["Spaces instead of tabs"] = re.compile('   ')
51cppRules["Missing space after control statement"] \
52    = re.compile('(for|if|while|switch)\(')
53cppRules["Missing space at comment start"] = re.compile('//\w')
54cppRules["Missing space after operator"] \
55    = re.compile('\w(==|[,=>/+\-*;\|])\w')
56cppRules["Operator at line end"] = re.compile('([*=/+\-\|\&\?]|\&&|\|\|)(?=\n)')
57cppRules["Missing space"] = re.compile('\){')
58cppRules["Mixed tabs/spaces"] = re.compile('( \t]|\t )+')
59cppRules["Malformed else"] = re.compile('}[ \t]*\n[ \t]*else')
60cppRules["Lines between functions > 2"] \
61    = re.compile('(?<=\n})([ \t]*\n){3,}(?=\n)')
62cppRules["Lines between functions < 2"] \
63    = re.compile('(?<=\n})([ \t]*\n){0,2}(?=.)')
64cppRules["Windows Line Ending"] = re.compile('\r')
65cppRules["Bad pointer/reference style"] \
66    = re.compile('(?<=\w) [*&](?=(\w|[,\)]))')
67
68# TODO: ignore some rules in comments
69#cppRules["-Comment 1"] = re.compile('[^/]/\*(.|[\r\n])*?\*/')
70#cppRules["-Comment 2"] = re.compile('(//)[^\n]*')
71
72
73if len(sys.argv) >= 2 and sys.argv[1] != "--help":
74    files = []
75    for arg in sys.argv[1:]:
76        if os.path.isfile(arg):
77            files.append(arg)
78        else:
79            os.path.walk(arg, visit, files)
80    run(files, cppRules, "styleviolations.html")
81else:
82    print "Usage: python checkstyle.py file.cpp [file2.cpp] [directory]\n"
83    print "Checks c++ source files against the Haiku Coding Guidelines."
84    print "Outputs an html report in the styleviolations.html file.\n"
85