#!/usr/bin/python import signal import sys import os import re if len(sys.argv) < 2: print("Usage:\t{0} FILE...".format(sys.argv[0])) sys.exit(1) def printError(file, type, line = -1): if line >= 0: print("{0} in {1}:{2}".format(type, file, line)) else: print("{0} for {1}".format(type, file)) def checkFile(path): if os.path.isdir(path): checkDir(path) else: baseName = os.path.basename(path) if baseName.upper() == "AUTHORS": if baseName != "AUTHORS": printError(path, "Bad filename") checkAuthors(path) if baseName[len(baseName)-1] == '~' or baseName[len(baseName)-1] == '#'\ or baseName[0] == '#': printError(path, "This is a temporary file") iExt = baseName.rfind('.') if iExt > 0: ext = baseName[iExt:] if ext == ".c": checkCFile(path) elif ext == ".h": checkHFile(path) elif ext == ".sh": checkSHFile(path) else: checkOtherFile(path) def checkDir(path): dirList = os.listdir(path) filesList = [] for f in dirList: basename = os.path.basename(f) if os.path.isdir(f): if basename == ".git" or basename == ".hg": printError(path, "There is a {0} repository".format(basename)) else: if basename[0] == '.': printError(path + '/' + basename, "Hidden directory") checkDir(path + '/' + f) else: if basename[0] == '.': printError(path + '/' + basename, "Hidden file") checkFile(path + '/' + f) def checkCComment(path, line, num): txt = line.strip() if re.match("\*/", txt) is not None: if re.match("\*/$", txt) is None: printError(path, "Last big comment lines aren't empty", num) return 0 elif re.match("\*/", txt) is not None and \ re.match("/\*", txt) is None: printError(path, "\*/ ", num) elif re.match("^\*\* ", txt) is None: printError(path, "Bad intermediary comment lines", num) return 1 def checkCLang(path, line, num): txt = line.strip() if re.match("^#define", txt) is not None and \ re.match("^#define +[A-Z0-9_]+[ (]?", txt) is None: printError(path, "Constant or macro without full uppercase", num) elif re.match("^ +#", line) is not None: printError(path, "The preprocessor directive mark not on the first column", num) elif re.match(".*sizeof[^ ].*", txt) is not None: printError(path, "Forgotten space after keyword", num) elif re.match("^# *(else|endif)", txt) is not None and \ re.match("^# *(else|endif) +/", txt) is None: printError(path, "Preprocesor condition without comment describing the corresponding condition", num) elif re.match("^(typedef +)?struct", txt) is not None and \ re.match("^(typedef +)?struct +s_", txt) is None: printError(path, "New struct without s_ name", num) elif re.match("^(typedef +)?union", txt) is not None and \ re.match("^(typedef +)?union +u_", txt) is None: printError(path, "New union without u_ name", num) elif re.match("^(typedef +)?enum", txt) is not None and \ re.match("^(typedef +)?enum +e_", txt) is None: printError(path, "New struct without s_ name", num) elif re.match("^typedef *(^(union|struct|enum))", txt) is not None and \ re.match("^typedef +(unsigned )?[a-z_\*] +t_", txt) is None: printError(path, "New type without t_ name", num) elif re.match("^(if|else|elseif|for|while|do|typedef|struct|return|sizeof)", txt) is not None and \ re.match("^(if|else|elseif|for|while|do|typedef|struct|return|sizeof)(uble| |$)", txt) is None: printError(path, "Forgotten space after keyword", num) elif re.match("^(if|else|elseif|for|while|do|typedef|struct)", txt) is not None and \ re.match("^(if|else|elseif|for|while|do|typedef|struct).*\{", txt) is not None: printError(path, "{ on the same line of instruction", num) elif re.match("(^/\*|\*/$)", txt) is not None and \ re.match("^(/\*|\*/)$", txt) is None: printError(path, "First and last big comment lines aren't empty", num) elif re.match("/\*$", txt) is not None: return 1 elif re.match("^for", txt) is not None and \ re.match("^for \(.*; .*; .*\)", txt) is None: printError(path, "Bad syntax for a for", num) elif re.match("^return", txt) is not None and \ re.match("^return \(.*\)", txt) is None: printError(path, "Bad syntax for return", num) elif re.match(".*[^=]=.*;", txt) is not None and \ re.match(".* [><]?[-&%+^*/!><|]?= .*", txt) is None: printError(path, "Bad syntax for an affectation", num) elif re.match("\r$", txt) is not None: printError(path, "DOS CR+LF line terminator detected", num) return 0 def checkHFile(path): checkCFile(path) num = 0 with open(path, "r") as fp: lines = fp.read().split('\n') #Search for Header protection for line in lines: num += 1 line = line.replace(" ", " ") def checkCFile(path): num = 0 with open(path, "r") as fp: lines = fp.read().split('\n') typeBlock = 0 for line in lines: num += 1 line = line.replace(" ", " ") check80cols(path, line, num) checkTrailingWhitespace(path, line, num) if typeBlock == 1: typeBlock = checkCComment(path, line, num) else: typeBlock = checkCLang(path, line, num) #Define some constants i = 1 while i < len(sys.argv): checkFile(sys.argv[i]) i += 1