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