config.h.1stpass
git.kdev4
.kdev4
+*.pyc
+*.pyo
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+"""
+ Runs all enabled style checking
+"""
+
+import sys, re, string
+from common_modules.common import *
+
+from check_license import check_license_in_file
+from check_header_guards import check_header_guards
+from check_consistent_code_style import check_consistent_code_style
+from check_indentation import check_indentation
+from check_curly_braces_alone_on_line import check_curly_braces_alone_on_line
+from check_long_lines import check_long_lines
+from check_single_definition_on_line import check_single_definition_on_line
+from check_single_statement_on_line import check_single_statement_on_line
+from check_tabbing_and_spacing import check_tabbing_and_spacing
+from check_empty_lines import check_empty_lines
+from check_class_name import check_class_name
+
+#######################################################################################################################
+#CONFIGURATION
+#######################################################################################################################
+CHECK_LICENSE = "ON"
+CHECK_HEADER_GUARDS = "ON"
+CHECK_TABBING_AND_SPACING = "ON"
+CHECK_INDENTATION = "ON"
+CHECK_CONSISTENT_CODE_STYLE = "ON"
+CHECK_CURLY_BRACES_ALONE_ON_LINE = "ON"
+CHECK_LONG_LINES = "ON"
+CHECK_SINGLE_STATEMENT_ON_LINE = "ON"
+CHECK_SINGLE_DEFINITION_ON_LINE = "ON"
+CHECK_EMPTY_LINES = "ON"
+CHECK_CLASS_NAME = "ON"
+#######################################################################################################################
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\tTakes a list of files and directories as input and runs all enabled style-checking on all files.
+
+\tTo enable/disable style-checking you can toggle the "ON"/"OFF" value of the configuration variables inside the file.
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2:] == ".c":
+ file_contents, clean_file_contents, file_lines, clean_file_lines = read_file(t)
+
+ if CHECK_LICENSE == "ON":
+ check_license_in_file(t, file_contents)
+ if CHECK_HEADER_GUARDS == "ON" and t[-2:] == ".h":
+ check_header_guards(t, file_contents)
+ if CHECK_TABBING_AND_SPACING == "ON":
+ check_tabbing_and_spacing(t, file_lines)
+ if CHECK_INDENTATION == "ON":
+ check_indentation(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
+ if CHECK_CONSISTENT_CODE_STYLE == "ON":
+ check_consistent_code_style(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
+ if CHECK_CURLY_BRACES_ALONE_ON_LINE == "ON":
+ check_curly_braces_alone_on_line(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
+ if CHECK_LONG_LINES == "ON":
+ check_long_lines(t, file_lines)
+ if CHECK_SINGLE_STATEMENT_ON_LINE == "ON":
+ check_single_statement_on_line(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
+ if CHECK_SINGLE_DEFINITION_ON_LINE == "ON":
+ check_single_definition_on_line(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
+ if CHECK_EMPTY_LINES == "ON":
+ check_empty_lines(t, file_contents, file_lines)
+ if CHECK_CLASS_NAME == "ON" and t[-2:] == ".h":
+ check_class_name(t, clean_file_contents)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+
+def check_class_name(filename, clean_file_contents):
+ #a class is followed by classname, and possible an inherticance
+ class_def_re = re.compile(r'(?<!\w)class(\s+)(\w+)(\s*)((:( |\w|,)*)?)(\s*)\{')
+ class_name_re = re.compile(r'(?<=((?<!\w)class))(\s+\w+)')
+
+ #filename without path and extension
+ good_name = filename
+
+ #remove path from filename (if needed)
+ if good_name.count("/") > 0:
+ good_name = good_name[good_name.rfind("/") + 1:]
+
+ #remove .h extension
+ good_name = good_name[:good_name.find(".h")]
+
+ class_found = False
+
+ for class_match in re.finditer(class_def_re, clean_file_contents):
+ line_number = clean_file_contents[:class_match.end()].count("\n")
+
+ if class_found:
+ log_warning(filename, line_number, "several class difinitions in file")
+ else:
+ class_found = True
+
+ class_name_match = class_name_re.search(clean_file_contents, class_match.start())
+ class_name = clean_file_contents[class_name_match.start(): class_name_match.end()] if class_name_match != None else ""
+ class_name = class_name.strip(" \n\r\f\t")
+
+ if class_name != good_name:
+ log_warning(filename, line_number, "class name has to be identical to filename")
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories.
+
+\tGives warnings if a file contains more than one class definition or if class name is not identical to file name
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h":
+ _, clean_file_contents, _, _= read_file(t)
+ check_class_name(t, clean_file_contents)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+
+
+def check_binary_operators(filename, file_contents, file_lines, clean_file_contents, clean_file_lines):
+ #normal binary operators must all have 0 or 1 space between operator and operands
+ binary_ops = ['=', r'\+', '%', r'\^', '==', '!=', '>=', '<=', '&&', r'\|\|', r'\|', '<<', '>>', r'\+=', '-=', r'\*=', '/=', '%=', '&=', r'\|=', r'\^=', '<<=', '>>=', ':', r'\?']
+ #operators that are not handled
+ #r'\*', '&', '>', '<', '/', '-'
+ #access binary operators must have no space between operator and operands
+ binary_ops_re_text = '(' + "|".join(binary_ops) + ')'
+
+ #re for NO space between operator and operands
+ nospace_re = re.compile(r"\w{0}\w".format(binary_ops_re_text))
+ #re for ONE space between operator and operands
+ space_re = re.compile(r"\w\s{0}\s\w".format(binary_ops_re_text))
+ #unbalanced is a match for binary op (\w\s*{0}\s*\w) that is neither no space (?!(\w{0}\w)) nor single space (?!(\w\s{0}\s\w))
+ #this works because (?!...) does not consume strings
+ unbalanced_spaces_re = re.compile(r"(?!(\w{0}\w))(?!(\w\s{0}\s\w))(\w\s*{0}\s*\w)".format(binary_ops_re_text))
+
+ #access_ops = ['.', '->', '::']
+ access_ops_re_text = r'(\.|->|::)'
+ bad_access_ops_re = re.compile(r"(\w\s+{0}\s*\w)|(\w\s*{0}\s+\w)".format(access_ops_re_text))
+
+ #check if there is general inconsistance in the file
+ nospace_match = re.search(nospace_re, clean_file_contents)
+ space_match = re.search(space_re, clean_file_contents)
+
+ if nospace_match != None and space_match != None:
+ line1 = clean_file_contents[:nospace_match.start()].count("\n") + 1
+ line2 = clean_file_contents[:space_match.start()].count("\n") + 1
+
+ log_warning(filename, line1, "inconsistent spacing between operands and binary operator. All operands in a file must have same space (0 or 1 spaces) [Reported once per file]", "lines :{0} and {1}".format(line1, line2))
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ if re.search(unbalanced_spaces_re, line) != None:
+ log_warning(filename, i + 1, "incorrect or unbalanced spaces between operands and binary operator", file_lines[i].strip(" "))
+
+ if re.search(bad_access_ops_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) around access/resolution operator", file_lines[i].strip(" "))
+
+def check_semicolor(filename, file_contents, file_lines, clean_file_contents, clean_file_lines):
+ #check if there is extra space before semicolon, or missing space after semicolon (if there is content after it like in for loop)
+ space_before_re = re.compile(r"\s;");
+ nospace_after_re = re.compile(r";((?! ).)");
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ if re.search(space_before_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) before semicolon", file_lines[i].strip(" "))
+
+ if re.search(nospace_after_re, line) != None:
+ log_warning(filename, i + 1, "missing space after semicolon", file_lines[i].strip(" "))
+
+def check_braces_spaces(filename, file_contents, file_lines, clean_file_contents, clean_file_lines):
+ #check if there are spaces between between right/left brace and contents
+ bad_left_brace_re = re.compile(r"\(\s")
+ bad_right_brace_re = re.compile(r"\s\)")
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ if re.search(bad_left_brace_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) after left brace", file_lines[i].strip(" "))
+
+ if re.search(bad_right_brace_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) before right brace", file_lines[i].strip(" "))
+
+def check_commas(filename, file_contents, file_lines, clean_file_contents, clean_file_lines):
+ nospace_after_re = re.compile(r",((?!\s).)")
+ too_many_spaces_after_re = re.compile(r",\s(\s+)")
+ space_before_re = re.compile(r"\S(\s+),")
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ if re.search(nospace_after_re, line) != None:
+ log_warning(filename, i + 1, "missing space after comma", file_lines[i].strip(" "))
+
+ if re.search(too_many_spaces_after_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) after comma", file_lines[i].strip(" "))
+
+ if re.search(space_before_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) before comma", file_lines[i].strip(" "))
+
+def check_function_call_or_definition(filename, file_contents, file_lines, clean_file_contents, clean_file_lines):
+ #in bad function definition or call there exists a space (or more) between function name and left brace (the last \s+ in the expression)
+ #the function name must not be a if, for, switch or while
+ reserved_words = ['if', 'for', 'while', 'switch', 'return', 'delete']
+ reserved_words_re_text = "(?<!\W" + ")(?<!\W".join(reserved_words) + ")"
+
+ #the bad function is anything except the reserved words, and the closing brace is not directly followed by another open brace
+ #(to differentiate function calls/defs from function pointer defs)
+ #the \s+ is the fauled pattern that should be caught, because it means a space exists between function name and left parenthese
+ bad_func_re_text = r"(\w+){0}(\s+)(\()".format(reserved_words_re_text)
+ bad_func_re = re.compile(bad_func_re_text)
+
+ #function pointer
+ return_type_re_text = r'\w+\s*(&|\*)*\s*'
+ func_ptr_re_text = r'\s*{0}\((\w|\*|:|\s)+\)(\s*)\('.format(return_type_re_text)
+
+ func_ptr_re = re.compile(func_ptr_re_text)
+
+ macro_re = re.compile(r"(\s*)#define")
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ for bad_func_match in bad_func_re.finditer(line):
+ #print line[bad_func_match.start():], re.match(func_ptr_re, line[bad_func_match.start():]) != None
+ if re.search(func_ptr_re, line) == None and re.match(macro_re, line) == None:
+ log_warning(filename, i + 1, "unneeded space(s) between function name and left brace", file_lines[i].strip(" "))
+
+def check_space_before_braces(filename, file_contents, file_lines, clean_file_contents, clean_file_lines):
+ reserved_words = ['if', 'for', 'while', 'switch', 'return']
+ reserved_words_re_text = r'\W(' + "|".join(reserved_words) + ')'
+
+ nospace_re = re.compile(r"{0}\(".format(reserved_words_re_text))
+ space_re = re.compile(r"{0}\s\(".format(reserved_words_re_text))
+ too_many_space_re = re.compile(r"{0}\s(\s+)\(".format(reserved_words_re_text))
+
+ nospace_match = re.search(nospace_re, clean_file_contents)
+ space_match = re.search(space_re, clean_file_contents)
+ if nospace_match != None and space_match != None:
+ line1 = clean_file_contents[:nospace_match.start()].count("\n") + 1
+ line2 = clean_file_contents[:space_match.start()].count("\n") + 1
+
+ log_warning(filename, line1, "inconsistent spacing between keyword and left brace. All braces in a file must have same space (0 or 1 spaces) [Reported once per file]", "lines :{0} and {1}".format(line1, line2))
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ if re.search(too_many_space_re, line) != None:
+ log_warning(filename, i + 1, "unneeded space(s) between keyword and left brace", file_lines[i].strip(" "))
+
+def check_consistent_code_style(filename, file_contents, clean_file_contents, file_lines, clean_file_lines):
+ check_function_call_or_definition(filename, file_contents, file_lines, clean_file_contents, clean_file_lines)
+ check_semicolor(filename, file_contents, file_lines, clean_file_contents, clean_file_lines)
+ check_space_before_braces(filename, file_contents, file_lines, clean_file_contents, clean_file_lines)
+ check_braces_spaces(filename, file_contents, file_lines, clean_file_contents, clean_file_lines)
+ check_commas(filename, file_contents, file_lines, clean_file_contents, clean_file_lines)
+ check_binary_operators(filename, file_contents, file_lines, clean_file_contents, clean_file_lines)
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories
+
+\tGives warnings if there is inconsistency in spacing of commas, semicolons, operands, braces, function calls or definitions.
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ file_contents, clean_file_contents, file_lines, clean_file_lines = read_file(t)
+ check_consistent_code_style(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+def remove_tollerable_braces(clean_file_contents):
+ #remove array assignments
+ assignment_re = re.compile(r'=(\s*)(\{)((?!;).)*(\})(\s*);', re.DOTALL)
+
+ no_assig_contents = clean_file_contents
+ found_match = re.search(assignment_re, no_assig_contents)
+
+ while found_match != None:
+ matched_string = no_assig_contents[found_match.start(): found_match.end()]
+ no_assig_contents = no_assig_contents[:found_match.start()] + "\n" * matched_string.count("\n") + no_assig_contents[found_match.end():]
+
+ found_match = re.search(assignment_re, no_assig_contents)
+
+ #remove braces that are used for implementing empty functions
+ empty_func_re = re.compile(r'\{\s*\}')
+
+ no_empty_func_contents = no_assig_contents
+ found_match = re.search(empty_func_re, no_empty_func_contents)
+
+ while found_match != None:
+ matched_string = no_empty_func_contents[found_match.start(): found_match.end()]
+ no_empty_func_contents = no_empty_func_contents[:found_match.start()] + "\n" * matched_string.count("\n") + no_empty_func_contents[found_match.end():]
+
+ found_match = re.search(empty_func_re, no_empty_func_contents)
+
+ return no_empty_func_contents
+
+def check_curly_braces_alone_on_line(filename, file_contents, clean_file_contents, file_lines, clean_file_lines):
+ clean_file_contents = remove_tollerable_braces(clean_file_contents)
+ clean_file_lines = clean_file_contents.split('\n')
+
+ typedecl_stack = []
+ #a type declaration contains the words struct, class , union or enum
+ typedecl_re = re.compile(r"(?!<\w)(typedef)?(\s*)(struct|class|enum|union)(?!\w)")
+ #some statements are allowed to have curly brace on same
+ permissible_re = re.compile(r'''(\s*)
+ (
+ do| # do keyword
+ (namespace((?!\{).)*)| # namespace keyword
+ (extern((?!\{).)*) # extern keyword
+ )?
+ (\s*)\{(\s*)
+ (\\?)(\s*)
+ $''', re.VERBOSE)
+
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ def get_former_line():
+ if i > 0:
+ for j in range(i - 1, 0 , -1):
+ if len(clean_file_lines[j].strip(" \t\n\f\r")):
+ return clean_file_lines[j]
+ return None
+
+ former_line = get_former_line()
+
+ if line.count("{"):
+ typedecl = re.search(typedecl_re, former_line)
+ typedecl_stack.append(typedecl)
+
+ if re.match(permissible_re, line) == None :
+ log_warning(filename, i + 1, "other code on same line with curly brace", file_lines[i].strip(" "))
+
+ if line.count("}"):
+ typedecl = typedecl_stack.pop()
+ if typedecl:
+ if re.match(r"(\s*)\}", line) == None:
+ log_warning(filename, i + 1, "other code on same line with curly brace", file_lines[i].strip(" "))
+ else:
+ if re.match(r"(\s*)\}(\s*)((while((?!;).)*)?)(;?)(\s*)(\\?)(\s*)$", line) == None:
+ log_warning(filename, i + 1, "other code on same line with curly brace", file_lines[i].strip(" "))
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories
+
+\tGives warnings if unnecessary code exists on the same line with curly braces.
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ file_contents, clean_file_contents, file_lines, clean_file_lines = read_file(t)
+ check_curly_braces_alone_on_line(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+from common_modules.config import G_MAX_INDENTATION_THRESHOLD
+
+
+def check_empty_lines(filename, file_contents, file_lines):
+ #keep track of the current indentation
+ #need only to know if level of indent is zero or not
+ line_indent_zero = True
+
+ def is_line_empty(l):
+ return len(l.strip(" \t\n\r\f")) == 0
+
+ #check all lines except last line
+ for i in range(len(file_lines) - 1):
+ line = file_lines[i]
+ former_line = file_lines[i - 1] if i > 0 else ""
+ next_line = file_lines[i + 1] if i < len(file_lines) - 1 else ""
+
+ def is_next_indent_zero():
+ for j in range(i + 1, len(file_lines)):
+ if not is_line_empty(file_lines[j]):
+ return re.match(r'(\s+)(\S+)', file_lines[j]) == None
+ return True
+
+ next_indent_zero = is_next_indent_zero()
+
+ #if empty line
+ if is_line_empty(line):
+ #check if line is not needed
+ #if the line before it was empty (two consecutive white space lines)
+ if is_line_empty(former_line) and not line_indent_zero and not next_indent_zero:
+ log_warning(filename, i + 1, "unneeded empty line (two or more consecutive empty lines)")
+ #if the line before it was a block beginning
+ elif re.search(r'\{(\s*)$', former_line):
+ log_warning(filename, i + 1, "unneeded empty line (block begins with empty line)")
+ #if the line after it is a block end
+ elif re.match(r'(\s*)\}', next_line):
+ log_warning(filename, i + 1, "unneeded empty line (block ends with empty line)")
+ #if non-empty line
+ else:
+ #if the line contains one or more white-space characters followed by
+ #one or more non white-space characters
+ line_indent_zero = re.match(r'(\s+)(\S+)', line) == None
+
+ if re.search(r'\n$', file_contents) == None:
+ log_warning(filename, len(file_lines), "file does not end with new line")
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories
+
+\tGives warnings if there are unneeded empty lines
+\tIt also gives a warning if there is NO empty line at end of file (because this leads to warnings on some compilers)
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ file_contents, _, file_lines, _ = read_file(t)
+ check_empty_lines(t, file_contents, file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+def check_header_guards(filename, file_contents):
+ #remove strings
+ string_re = re.compile(r'"((?!((?<!((?<!\\)\\))")).)*"', re.DOTALL)
+ file_contents = clean_string_from_regex(file_contents, string_re, 'x')
+
+ #remove multi-line comments
+ ml_comment_re = re.compile(r'(\s*)/\*((?!\*/).)*\*/', re.DOTALL)
+ file_contents = clean_string_from_regex(file_contents, ml_comment_re, '')
+
+ #remove single line comments
+ sl_comment_re = re.compile("//.*$", re.MULTILINE)
+ file_contents = re.sub(sl_comment_re, '', file_contents)
+
+ file_contents = file_contents.strip(" \t\n\f\r")
+
+
+ def check_good_name(name):
+ #good name
+ good_name = filename
+
+ #remove path from filename (if needed)
+ if good_name.count("/") > 0:
+ good_name = good_name[good_name.rfind("/") + 1:]
+
+ #remove .h extension
+ good_name = good_name[:good_name.find(".h")]
+
+ #good name is all uppercase
+ good_name = good_name.upper()
+
+ #a good name can start with underscores, and can end with underscores, can optionally have a capital H character
+ good_name_re = re.compile("(_*){0}(_+H?_*)?".format(good_name))
+
+ return re.match(good_name_re, name) != None
+
+ #find the ifndef guard
+ ifndef_re = re.compile(r"(\s*)#ifndef .*", re.MULTILINE)
+ ifndef_match = re.match(ifndef_re, file_contents)
+ if ifndef_match == None:
+ log_warning(filename, 1, "header file does not contain a valid #ifndef guard at the beginning")
+ return None
+
+ ifndef_match_text = file_contents[:ifndef_match.end()]
+ ifndef_match_text = ifndef_match_text.strip(" \n\r\f\t")
+ splitted_match_text = ifndef_match_text.split(" ")
+ ifndef_guard_name = splitted_match_text[1] if len(splitted_match_text) > 1 else ""
+
+ if not check_good_name(ifndef_guard_name):
+ log_warning(filename, 1, "#ifndef {0} guard name does not follow convention, name has to contain file name in uppercase".format(ifndef_guard_name))
+ return None
+
+ file_contents = file_contents[ifndef_match.end():]
+
+ #find the define guard
+ define_re = re.compile(r"(\s*)#define .*")
+ define_match = re.match(define_re, file_contents)
+ if define_match == None:
+ log_warning(filename, 1, "header file does not contain a #define guard at the beginning that matches #ifndef {0}".format(ifndef_guard_name))
+ return None
+
+ define_match_text = file_contents[:define_match.end()]
+ define_match_text = define_match_text.strip(" \n\r\f\t")
+ splitted_match_text = define_match_text.split(" ")
+ define_guard_name = splitted_match_text[1] if len(splitted_match_text) > 1 else ""
+
+ if define_guard_name != ifndef_guard_name:
+ log_warning(filename, 1, "header guard names do not match :(#ifndef {0}) and (#define {1})".format(ifndef_guard_name, define_guard_name))
+
+ #find the endif guard
+ endif_re = re.compile(r"#endif.*(\s*)$")
+ endif_match = re.search(endif_re, file_contents)
+ if endif_match == None:
+ log_warning(filename, 1, "header file does not end with #endif at last line")
+ return None
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories
+
+\tGives warnings if header guards does not exist in header files. Header files must have a #ifndef and #define guards directly after the license.
+\tThe names of the header guards must match together and match with the name of the file in uppercase letters.
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h":
+ file_contents, _, _, _ = read_file(t)
+ check_header_guards(t, file_contents)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+from common_modules.config import G_MAX_INDENTATION_THRESHOLD
+
+def check_indentation(filename, file_contents, clean_file_contents, file_lines, clean_file_lines):
+ #It is important to keep track of the changes made to the indent level because
+ #curly braces of namespaces do not affect indentation, while curly braces of
+ #other statements like if, for and while increase/decease indentation
+ indent_levels_stack = [0]
+ indent_level = 0
+ parentheses_count = 0
+
+ def is_incomplete_statement(line, former_line):
+ incomplete_statement = False
+ #include statements not preceded by a semicolon in previous line
+ incomplete_statement |= former_line != None and re.search(re.compile(r";(\s*)$"), former_line) == None
+ #exclude lines containing block beginnings and ends
+ incomplete_statement &= re.search(re.compile(r"(\{|\})(\s*)$"), line) == None
+ #exclude statements preceded by block beginnings and ends
+ incomplete_statement &= former_line != None and re.search(re.compile(r"(\{|\})(\s*)$"), former_line) == None
+ #exclude preprocessor directives (they dunt have to end with a ; for example)
+ incomplete_statement &= re.match(re.compile(r"(\s*)#"), line) == None
+ #exclude statements preceded by preprocessor directives that do not end with a slash \
+ incomplete_statement &= former_line != None and re.match(re.compile(r"(\s*)#((?!\/).)*\/$"), former_line) == None
+
+
+ #filter out the case where a line is preceeded by a label statement
+ fl_label_statement = False
+ if former_line != None:
+ #case statements -> case id : expr that does not begin with a : (to avoid matching with :: operator)
+ fl_label_statement = re.match(r'(\s*)case(\s*)((?!:).)*(\s*):(?!:)(\s*)$', former_line) != None
+ #label statements -> label : expr that does not begin with a : (to avoid matching with :: operator)
+ fl_label_statement |= re.match(r'(\s*)(\w+)(\s*):(?!:)(\s*)$', former_line) != None
+
+ incomplete_statement &= not fl_label_statement
+
+ #include statements that are contained inside parentheses
+ incomplete_statement |= parentheses_count > 0
+
+ return incomplete_statement
+
+ def is_label_statement(line):
+ label_statement = False
+ if line != None:
+ #case statements -> case id : expr that does not begin with a : (to avoid matching with :: operator)
+ label_statement = re.match(r'(\s*)case(\s*)((?!:).)*(\s*):(?!:)', line) != None
+ #label statements -> label : expr that does not begin with a : (to avoid matching with :: operator)
+ label_statement |= re.match(r'(\s*)(\w+)(\s*):(?!:)', line) != None
+ return label_statement
+
+ def is_preprocessor_directive(line):
+ return re.match(r"(\s*)#", line) != None
+
+ def is_macro_body(former_line):
+ return former_line != None and re.search(r"\\$", former_line) != None
+
+ for i in range(len(clean_file_lines)):
+ line = clean_file_lines[i]
+ line_indent = 0
+
+ #a loop is to account for cases where there are several braces on same line
+ for _ in range(0, line.count("}") - line.count("{")):
+ indent_level = indent_levels_stack.pop()
+
+ #check correct line indentation
+ found_match = re.search("(?! )", line)
+ if found_match:
+ line_indent = found_match.start() / 4.0
+
+ def get_former_line():
+ if i > 0:
+ for j in range(i - 1, 0 , -1):
+ if len(clean_file_lines[j].strip(" \t\n\f\r")):
+ return clean_file_lines[j]
+ return ""
+
+ former_line = get_former_line()
+
+ incomplete_statement = is_incomplete_statement(line, former_line)
+ label_statement = is_label_statement(line)
+ fl_label_statement = is_label_statement(former_line)
+ preprocessor_directive = is_preprocessor_directive(line)
+ macro_body = is_macro_body(former_line)
+
+ if len(line.strip(" \t\n\r")) > 0:
+ if macro_body:
+ #do not check anything, just ignore line
+ None
+ elif preprocessor_directive:
+ #warning if not at 0 level indentation
+ if line_indent != 0:
+ log_warning(filename, i + 1, "incorrect indentation", file_lines[i].strip(" "))
+ elif label_statement:
+ #warning if label statement has one level less indentation than the normal indentation level
+ if line_indent != indent_level - 1:
+ log_warning(filename, i + 1, "incorrect indentation", file_lines[i].strip(" "))
+ elif (not incomplete_statement) and line_indent != indent_level:
+ #warning if a complete statement (NON incomplete statement) is not at the normal level of indentation
+ log_warning(filename, i + 1, "incorrect indentation", file_lines[i].strip(" "))
+ elif incomplete_statement:
+ if fl_label_statement and line_indent != indent_level:
+ #warning if preceeded by a label statement but not exactly at normal indentation
+ log_warning(filename, i + 1, "incorrect indentation", file_lines[i].strip(" "))
+ elif (not fl_label_statement ) and line_indent < indent_level:
+ #warning if incomplete statement and indentation is less than normal indentation
+ log_warning(filename, i + 1, "incorrect indentation", file_lines[i].strip(" "))
+
+ #a loop is to account for cases where there are several braces on same line
+ for _ in range(0, line.count("{") - line.count("}")):
+ indent_levels_stack.append(indent_level)
+ #if there is no namesapce or extern declaration before curly brace: increase indentation
+ #if re.match(r"(\s*)((namespace(\s+\w+)?(\s*)\{)|(extern(((?!\{).)*)\{))", line) == None and re.match(r"(\s*)(namespace|extern)", former_line) == None:
+ #if re.match(r"(\s*)(namespace)", line) == None and re.match(r"(\s*)namespace", former_line) == None:
+ namespace_or_extern_re_text = r'\s*(namespace|(extern((\s*\S*\s*)?)(\s*)($|\{)))'
+ namespace_or_extern_re = re.compile(namespace_or_extern_re_text)
+
+ if re.match(namespace_or_extern_re, line) == None and re.match(namespace_or_extern_re, former_line) == None:
+ indent_level += 1
+
+ #warning if indentation level is too much
+ if indent_level == G_MAX_INDENTATION_THRESHOLD + 1:
+ log_warning(filename, i + 1, "code block has too much indentation [maximum level of indentation is {0}]".format(G_MAX_INDENTATION_THRESHOLD),)
+
+ parentheses_count += line.count("(") - line.count(")")
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories
+
+\tGives warnings if lines (except multi-line comments and macros) do not have correct indentation.
+\tIt also checks if code blocks have too much indentation (too deep). Code should have a maximum of {0} indentation levels.
+""".format(G_MAX_INDENTATION_THRESHOLD)
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ file_contents, clean_file_contents, file_lines, clean_file_lines = read_file(t)
+ check_indentation(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+BMW_LICENSE_TEMPLATE = '''/***************************************************************************
+*
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+****************************************************************************/'''
+
+
+def clean_comment_chars(s):
+ """
+ Removes comment characters from a string
+ """
+ s = string.replace(s, "/", "")
+ s = string.replace(s, "*", "")
+ s = string.replace(s, "#", "")
+ return s
+
+def make_license_re(license_text):
+ """
+ Makes a regular expression for every line in the license, this would match the license
+ text tolerating extra spaces
+ """
+ license_lines = license_text.split("\n")
+ license_lines_re = {}
+ for i in range(len(license_lines)):
+ license_line = license_lines[i]
+ re_text = clean_comment_chars(license_line)
+ re_text = re_text.strip(" \n\t\r\f")
+ re_text = string.replace(re_text, "(", "\(")
+ re_text = string.replace(re_text, ")", "\)")
+ re_text = string.replace(re_text, " ", "(\s+)")
+ re_text = string.replace(re_text, "\n", "(\s*)")
+ re_text = string.replace(re_text, "\t", "(\s+)")
+ re_text = string.replace(re_text, ".", "\.")
+
+ re_text = string.replace(re_text, "[YYYY]", r"(\d{4})(((-(\d{4}))|(((\s*),(\s*)\d{4})+))?)")
+
+ if len(re_text) > 0:
+ re_text = "(\s*)" + re_text + "(\s*)"
+ current_text = ""
+ while current_text != re_text:
+ current_text = re_text
+ re_text = string.replace(re_text, "(\s*)(\s*)", "(\s*)")
+ re_text = string.replace(re_text, "(\s+)(\s+)", "(\s+)")
+ re_text = string.replace(re_text, "(\s*)(\s+)", "(\s+)")
+
+
+ license_lines_re[i] = re_text
+
+ return license_lines_re
+
+
+def check_license_in_file(filename, file_contents):
+ clean_file_contents = clean_comment_chars(file_contents)
+ license_text = BMW_LICENSE_TEMPLATE
+
+ license_lines = license_text.split("\n")
+
+ license_re = make_license_re(license_text)
+
+ #search for the first line of the license in the target file
+ line_re = re.compile(license_re.values()[0])
+ found_match = line_re.search(clean_file_contents)
+
+ if found_match:
+ clean_file_contents = clean_file_contents[found_match.start():]
+
+ #check license as it is
+ for (line_num, line_re_text) in license_re.items():
+ line_re = re.compile(line_re_text)
+ found_match = line_re.match(clean_file_contents)
+
+ if found_match:
+ clean_file_contents = clean_file_contents[found_match.end():]
+ else:
+ log_warning(filename, 1, "license does not match at", license_lines[line_num])
+ return None
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories.
+
+\tGives warnings if the file does not contain a valid license text. It does not check if Copyright statements are included.
+"""
+ exit(0)
+
+ for t in targets:
+ file_contents, _, _, _ = read_file(t)
+ check_license_in_file(t, file_contents)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+from common_modules.config import G_MAX_LINE_LENGTH_THRESHOLD
+
+
+def check_long_lines(filename, file_lines):
+ string_re = re.compile(r'"((?!((?<!((?<!\\)\\))")).)*"', re.DOTALL)
+
+ for i in range(len(file_lines)):
+ line = file_lines[i]
+
+ #if line is very long and DOES NOT contain strings
+ if len(line) > G_MAX_LINE_LENGTH_THRESHOLD and re.search(string_re, line) == None:
+ log_warning(filename, i + 1, "line too long, {0} characters [maximum is {1}]".format(len(line), G_MAX_LINE_LENGTH_THRESHOLD))
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories.
+
+\tGives warnings if there are too long lines for readability. A line can have a maximum of {0} characters.
+""".format(G_MAX_LINE_LENGTH_THRESHOLD)
+ exit(0)
+
+ for t in targets:
+ _, _, file_lines, _ = read_file(t)
+ check_long_lines(t, file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+def check_single_definition_on_line(filename, file_contents, clean_file_contents, file_lines, clean_file_lines):
+ #variable name can be preceeded by * for pointers or & for references, can be followed by an assignment
+ var_decl_re_text = r"(((\**)|(&?))(\s*)(\w+)((=((?![,{]).)*)?))"
+ #types can be in namespaces or nested classes
+ no_template_type_re_text = r"\w+(::\w+)*"
+ simple_several_defs_re = re.compile(r"^(\s*){0}(\s+){1}((\s*),(\s*){1})+;".format(no_template_type_re_text, var_decl_re_text), re.MULTILINE)
+
+ for match in re.finditer(simple_several_defs_re, clean_file_contents):
+ line_number = clean_file_contents.count("\n", 0, match.end())
+ log_warning(filename, line_number + 1, "several definitions on same line", file_lines[line_number].strip(" \t\r\n"))
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories.
+
+\tGives warnings if a line contains several variable definitions (This does not include lines that contain template or array declarations).
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ file_contents, clean_file_contents, file_lines, clean_file_lines = read_file(t)
+ check_single_definition_on_line(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+def check_single_statement_on_line(filename, file_contents, clean_file_contents, file_lines, clean_file_lines):
+ open_parantheses_count = 0
+
+ for i in range(len(file_lines)):
+ line = clean_file_lines[i]
+
+ open_parantheses_count += line.count("(") - line.count(")")
+
+ #check if there are several semicolons on the line and that is not in the middle of a for statement
+ if line.count(";") > 1 and open_parantheses_count == 0:
+ #check that there is NO right parentheses after semicolon
+ if line.rfind(";") > line.rfind(")"):
+ log_warning(filename, i + 1, "several statements on same line", file_lines[i].strip(" "))
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories.
+
+\tGives warnings if a line contains several statements.
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ file_contents, clean_file_contents, file_lines, clean_file_lines = read_file(t)
+ check_single_statement_on_line(t, file_contents, clean_file_contents, file_lines, clean_file_lines)
--- /dev/null
+#!/bin/bash
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+
+
+DIRECTORY=$(cd `dirname $0` && pwd)
+cd $DIRECTORY
+cd ..
+
+echo $PWD
+echo "----------------------------------------"
+
+TEMP_FILENAME=".check_style_temp.`date +%s%N`"
+
+TARGET_FILES="`find -iname *.cpp -or -iname *.h -or -iname *.c | grep -vi \/tests\/ | grep -vi \/test\/ | grep -vi 3rdParty | grep -vi \/LayerManagerExamples\/ | grep -vi \config\/`"
+
+for t_file in $TARGET_FILES
+do
+ python scripts/check_all_styles.py $t_file | tee $TEMP_FILENAME -a
+done
+
+LINES=`cat $TEMP_FILENAME | wc -l`
+
+echo -e "\nTotal number of warnings: $LINES"
+rm $TEMP_FILENAME
\ No newline at end of file
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+import sys, re, string
+from common_modules.common import *
+
+def check_tabs_no_spaces(filename, file_lines):
+ for i in range(len(file_lines)):
+ if file_lines[i].count("\t") > 0:
+ log_warning(filename, i + 1, "tab character (\\t) found, use 4 spaces instead", file_lines[i].strip(" "))
+
+def check_correct_space_count(filename, file_lines):
+ in_multiline_comment = False
+ for i in range(len(file_lines)):
+ if in_multiline_comment:
+ if file_lines[i].count("*/") > 0:
+ in_multiline_comment = file_lines[i].count("/*") > 0 and file_lines[i].index("/*") > file_lines[i].index("*/")
+ else:
+ in_multiline_comment = file_lines[i].count("/*") > 0
+
+ found_match = re.search("(?! )", file_lines[i])
+ if found_match:
+ space_count = found_match.start()
+ if space_count % 4 != 0:
+ log_warning(filename, i + 1, "number of spaces at beginning of line must be divisible by 4")
+
+
+def check_no_spacing_line_end(filename, file_lines):
+ for i in range(len(file_lines)):
+ if re.search(" $", file_lines[i]):
+ log_warning(filename, i + 1, "unneeded space(s) at end of line")
+
+def check_tabbing_and_spacing(filename, file_lines):
+ check_tabs_no_spaces(filename, file_lines)
+ check_correct_space_count(filename, file_lines)
+ check_no_spacing_line_end(filename, file_lines)
+
+
+if __name__ == "__main__":
+ targets = sys.argv[1:]
+ targets = get_all_files(targets)
+
+ if len(targets) == 0:
+ print """
+\t**** No input provided ***
+\tTakes a list of files/directories as input and performs specific style checking on all files/directories.
+
+\tGives warnings if a line contains unneeded spaces at end of line, contains tab characters (\\t)
+\tor if spaces at line beginning are not divisible by 4.
+"""
+ exit(0)
+
+ for t in targets:
+ if t[-2:] == ".h" or t[-4:] == ".cpp" or t[-2] == ".c":
+ _, _, file_lines, _ = read_file(t)
+ check_tabbing_and_spacing(t, file_lines)
--- /dev/null
+#!/usr/bin/python
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+"""
+ Contains utility functions used by other modules
+"""
+
+import sys, re, string, os
+import config
+
+def clean_string_from_regex(s, regex, marker):
+ """
+ Removes all occurances of the passed regex from a string s, and puts instances of marker at the beginnings and ends
+ of remved substring
+ """
+
+ result = s
+ found_match = re.search(regex, result)
+
+ while found_match != None:
+ matched_string = result[found_match.start(): found_match.end()]
+ #replace by x...x where the ... is the \n chars in the matched string (to keep number of lines constant)
+ result = result[:found_match.start()] + marker + "\n" * matched_string.count("\n") + marker + result[found_match.end():]
+
+ found_match = re.search(regex, result)
+
+ return result
+
+def get_clean_file_contents(file_contents):
+ """
+ Removes strings, C style and C++ comments style comments and macros from file_contents
+ """
+
+ clean_file_contents = file_contents
+
+ #remove all strings
+ #a string is something that starts with a (") and ends with a ("), can have any character inside it except a (") that is not preceded by a slash (\) that is not preceded by another slash
+ #this means a string can contains a \\ escape sequence
+ #a string can contain a \" escape sequence
+ #a string can end with \\", but it does not end with \"
+ string_re = re.compile(r'"((?!((?<!((?<!\\)\\))")).)*"', re.DOTALL)
+
+ #'x' is passed as a marker, to mark the beginning and of strings
+ #to preserve spacing around string beginning and end
+ clean_file_contents = clean_string_from_regex(clean_file_contents, string_re, 'x')
+
+ #remove character literals
+ #a character literal is defined like a string (replacing single quotes with double quotes)
+ #this is a big relaxation of the problem for C/C++
+ char_re = re.compile(r'\'((?!((?<!((?<!\\)\\))\')).)*\'')
+
+ clean_file_contents = clean_string_from_regex(clean_file_contents, char_re, 'x')
+
+ #remove multi-line comments
+ ml_comment_re = re.compile(r'(\s*)/\*((?!\*/).)*\*/', re.DOTALL)
+ clean_file_contents = clean_string_from_regex(clean_file_contents, ml_comment_re, '')
+
+ #remove single line comments
+ sl_comment_re = re.compile(r'[ \t\r\f]*//.*$', re.MULTILINE)
+ clean_file_contents = re.sub(sl_comment_re, '', clean_file_contents)
+
+ #remove single-line and multi-line macros
+ #a macro is #define statement followed by a few statements that have a slash in the line before it
+ macro_re = re.compile(r'#define(\s+)(((?!\\).)+)((\\\n(((?!\\).)+))*)')
+ clean_file_contents = clean_string_from_regex(clean_file_contents, macro_re, '')
+
+ return clean_file_contents
+
+
+def read_file(filename):
+ """
+ Reads contents of the file, returns a 4-tuple containing:
+ 1- raw file contents
+ 2- file contents without comments, strings and macros
+ 3- raw file contents as lines
+ 4- file contents without comments, strings and macros as lines
+ """
+ file_contents = open(filename).read()
+ clean_file_contents = get_clean_file_contents(file_contents)
+
+ file_lines = file_contents.split("\n")
+ clean_file_lines = clean_file_contents.split("\n")
+
+ return (file_contents, clean_file_contents, file_lines, clean_file_lines)
+
+
+def get_all_files(targets):
+ """
+ Iterates over targets and gets names of all files
+ """
+ filenames = []
+ for t in targets:
+ #if directory: handle every file
+ if os.path.isdir(t):
+ for (path, _, files) in os.walk(t, followlinks=True):
+ for f in files:
+ filenames.append(os.path.abspath(os.path.join(path, f)))
+
+ #if file: process directly
+ else:
+ filenames.append(os.path.abspath(t))
+
+ return filenames
+
+def log_warning(filename, line_number, description, line_content = None):
+ """
+ Prints a warning to the standard output
+ """
+ if line_content == None:
+ print "{0}:{1}: warning: {2}".format(filename, line_number, description)
+ else:
+ print "{0}:{1}: warning: {2}: {3}".format(filename, line_number, description, line_content)
+
+ config.G_WARNING_COUNT += 1
+
+def get_warning_count():
+ """
+ Returns the number of reported warnings
+ """
+ return config.G_WARNING_COUNT
+
+
+
--- /dev/null
+
+###########################################################################
+#
+# Copyright 2013 BMW Car IT GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+###########################################################################
+
+"""
+ Contains configurations constants
+"""
+G_MAX_INDENTATION_THRESHOLD = 6
+G_MAX_LINE_LENGTH_THRESHOLD = 140
+G_WARNING_COUNT = 0