mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-21 05:04:45 +00:00
added libraries: opus flac libsndfile updated: libvorbis libogg openal - Everything works as expected for now. Bare in mind libsndfile needed the check for whether or not it could find the xiph libraries removed in order for this to work.
257 lines
7.9 KiB
Python
257 lines
7.9 KiB
Python
#!/usr/bin/python -tt
|
|
#
|
|
# Copyright (C) 2005-2017 Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
#
|
|
# Released under the 2 clause BSD license.
|
|
|
|
"""
|
|
This program checks C code for compliance to coding standards used in
|
|
libsndfile and other projects I run.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
|
|
|
|
class Preprocessor:
|
|
"""
|
|
Preprocess lines of C code to make it easier for the CStyleChecker class to
|
|
test for correctness. Preprocessing works on a single line at a time but
|
|
maintains state between consecutive lines so it can preprocessess multi-line
|
|
comments.
|
|
Preprocessing involves:
|
|
- Strip C++ style comments from a line.
|
|
- Strip C comments from a series of lines. When a C comment starts and
|
|
ends on the same line it will be replaced with 'comment'.
|
|
- Replace arbitrary C strings with the zero length string.
|
|
- Replace '#define f(x)' with '#define f (c)' (The C #define requires that
|
|
there be no space between defined macro name and the open paren of the
|
|
argument list).
|
|
Used by the CStyleChecker class.
|
|
"""
|
|
def __init__ (self):
|
|
self.comment_nest = 0
|
|
self.leading_space_re = re.compile ('^(\t+| )')
|
|
self.trailing_space_re = re.compile ('(\t+| )$')
|
|
self.define_hack_re = re.compile ("(#\s*define\s+[a-zA-Z0-9_]+)\(")
|
|
|
|
def comment_nesting (self):
|
|
"""
|
|
Return the currect comment nesting. At the start and end of the file,
|
|
this value should be zero. Inside C comments it should be 1 or
|
|
(possibly) more.
|
|
"""
|
|
return self.comment_nest
|
|
|
|
def __call__ (self, line):
|
|
"""
|
|
Strip the provided line of C and C++ comments. Stripping of multi-line
|
|
C comments works as expected.
|
|
"""
|
|
|
|
line = self.define_hack_re.sub (r'\1 (', line)
|
|
|
|
line = self.process_strings (line)
|
|
|
|
# Strip C++ style comments.
|
|
if self.comment_nest == 0:
|
|
line = re.sub ("( |\t*)//.*", '', line)
|
|
|
|
# Strip C style comments.
|
|
open_comment = line.find ('/*')
|
|
close_comment = line.find ('*/')
|
|
|
|
if self.comment_nest > 0 and close_comment < 0:
|
|
# Inside a comment block that does not close on this line.
|
|
return ""
|
|
|
|
if open_comment >= 0 and close_comment < 0:
|
|
# A comment begins on this line but doesn't close on this line.
|
|
self.comment_nest += 1
|
|
return self.trailing_space_re.sub ('', line [:open_comment])
|
|
|
|
if open_comment < 0 and close_comment >= 0:
|
|
# Currently open comment ends on this line.
|
|
self.comment_nest -= 1
|
|
return self.trailing_space_re.sub ('', line [close_comment + 2:])
|
|
|
|
if open_comment >= 0 and close_comment > 0 and self.comment_nest == 0:
|
|
# Comment begins and ends on this line. Replace it with 'comment'
|
|
# so we don't need to check whitespace before and after the comment
|
|
# we're removing.
|
|
newline = line [:open_comment] + "comment" + line [close_comment + 2:]
|
|
return self.__call__ (newline)
|
|
|
|
return line
|
|
|
|
def process_strings (self, line):
|
|
"""
|
|
Given a line of C code, return a string where all literal C strings have
|
|
been replaced with the empty string literal "".
|
|
"""
|
|
for k in range (0, len (line)):
|
|
if line [k] == '"':
|
|
start = k
|
|
for k in range (start + 1, len (line)):
|
|
if line [k] == '"' and line [k - 1] != '\\':
|
|
return line [:start + 1] + '"' + self.process_strings (line [k + 1:])
|
|
return line
|
|
|
|
|
|
class CStyleChecker:
|
|
"""
|
|
A class for checking the whitespace and layout of a C code.
|
|
"""
|
|
def __init__ (self, debug):
|
|
self.debug = debug
|
|
self.filename = None
|
|
self.error_count = 0
|
|
self.line_num = 1
|
|
self.orig_line = ''
|
|
self.trailing_newline_re = re.compile ('[\r\n]+$')
|
|
self.indent_re = re.compile ("^\s*")
|
|
self.last_line_indent = ""
|
|
self.last_line_indent_curly = False
|
|
self.re_checks = \
|
|
[ ( re.compile (" "), "multiple space instead of tab" )
|
|
, ( re.compile ("\t "), "space after tab" )
|
|
, ( re.compile ("[^ ];"), "missing space before semi-colon" )
|
|
, ( re.compile ("{[^\s}]"), "missing space after open brace" )
|
|
, ( re.compile ("[^{\s]}"), "missing space before close brace" )
|
|
, ( re.compile ("[ \t]+$"), "contains trailing whitespace" )
|
|
|
|
, ( re.compile (",[^\s\n]"), "missing space after comma" )
|
|
, ( re.compile (";[^\s]"), "missing space after semi-colon" )
|
|
, ( re.compile ("=[^\s\"'=]"), "missing space after assignment" )
|
|
|
|
# Open and close parenthesis.
|
|
, ( re.compile ("[^\s\(\[\*&']\("), "missing space before open parenthesis" )
|
|
, ( re.compile ("\)(-[^>]|[^,'\s\n\)\]-])"), "missing space after close parenthesis" )
|
|
, ( re.compile ("\s(do|for|if|when)\s.*{$"), "trailing open parenthesis at end of line" )
|
|
, ( re.compile ("\( [^;]"), "space after open parenthesis" )
|
|
, ( re.compile ("[^;] \)"), "space before close parenthesis" )
|
|
|
|
# Open and close square brace.
|
|
, ( re.compile ("[^\s\(\]]\["), "missing space before open square brace" )
|
|
, ( re.compile ("\][^,\)\]\[\s\.-]"), "missing space after close square brace" )
|
|
, ( re.compile ("\[ "), "space after open square brace" )
|
|
, ( re.compile (" \]"), "space before close square brace" )
|
|
|
|
# Space around operators.
|
|
, ( re.compile ("[^\s][\*/%+-][=][^\s]"), "missing space around opassign" )
|
|
, ( re.compile ("[^\s][<>!=^/][=]{1,2}[^\s]"), "missing space around comparison" )
|
|
|
|
# Parens around single argument to return.
|
|
, ( re.compile ("\s+return\s+\([a-zA-Z0-9_]+\)\s+;"), "parens around return value" )
|
|
|
|
# Parens around single case argument.
|
|
, ( re.compile ("\s+case\s+\([a-zA-Z0-9_]+\)\s+:"), "parens around single case argument" )
|
|
|
|
# Open curly at end of line.
|
|
, ( re.compile ("\)\s*{\s*$"), "open curly brace at end of line" )
|
|
|
|
# Pre and post increment/decrment.
|
|
, ( re.compile ("[^\(\[][+-]{2}[a-zA-Z0-9_]"), "space after pre increment/decrement" )
|
|
, ( re.compile ("[a-zA-Z0-9_][+-]{2}[^\)\,]]"), "space before post increment/decrement" )
|
|
]
|
|
|
|
def get_error_count (self):
|
|
"""
|
|
Return the current error count for this CStyleChecker object.
|
|
"""
|
|
return self.error_count
|
|
|
|
def check_files (self, files):
|
|
"""
|
|
Run the style checker on all the specified files.
|
|
"""
|
|
for filename in files:
|
|
self.check_file (filename)
|
|
|
|
def check_file (self, filename):
|
|
"""
|
|
Run the style checker on the specified file.
|
|
"""
|
|
self.filename = filename
|
|
cfile = open (filename, "r")
|
|
|
|
self.line_num = 1
|
|
|
|
preprocess = Preprocessor ()
|
|
while 1:
|
|
line = cfile.readline ()
|
|
if not line:
|
|
break
|
|
|
|
line = self.trailing_newline_re.sub ('', line)
|
|
self.orig_line = line
|
|
|
|
self.line_checks (preprocess (line))
|
|
|
|
self.line_num += 1
|
|
|
|
cfile.close ()
|
|
self.filename = None
|
|
|
|
# Check for errors finding comments.
|
|
if preprocess.comment_nesting () != 0:
|
|
print ("Weird, comments nested incorrectly.")
|
|
sys.exit (1)
|
|
|
|
return
|
|
|
|
def line_checks (self, line):
|
|
"""
|
|
Run the style checker on provided line of text, but within the context
|
|
of how the line fits within the file.
|
|
"""
|
|
|
|
indent = len (self.indent_re.search (line).group ())
|
|
if re.search ("^\s+}", line):
|
|
if not self.last_line_indent_curly and indent != self.last_line_indent:
|
|
None # self.error ("bad indent on close curly brace")
|
|
self.last_line_indent_curly = True
|
|
else:
|
|
self.last_line_indent_curly = False
|
|
|
|
# Now all the regex checks.
|
|
for (check_re, msg) in self.re_checks:
|
|
if check_re.search (line):
|
|
self.error (msg)
|
|
|
|
if re.search ("[a-zA-Z0-9][<>!=^/&\|]{1,2}[a-zA-Z0-9]", line):
|
|
if not re.search (".*#include.*[a-zA-Z0-9]/[a-zA-Z]", line):
|
|
self.error ("missing space around operator")
|
|
|
|
self.last_line_indent = indent
|
|
return
|
|
|
|
def error (self, msg):
|
|
"""
|
|
Print an error message and increment the error count.
|
|
"""
|
|
print ("%s (%d) : %s" % (self.filename, self.line_num, msg))
|
|
if self.debug:
|
|
print ("'" + self.orig_line + "'")
|
|
self.error_count += 1
|
|
|
|
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
|
|
if len (sys.argv) < 1:
|
|
print ("Usage : yada yada")
|
|
sys.exit (1)
|
|
|
|
# Create a new CStyleChecker object
|
|
if sys.argv [1] == '-d' or sys.argv [1] == '--debug':
|
|
cstyle = CStyleChecker (True)
|
|
cstyle.check_files (sys.argv [2:])
|
|
else:
|
|
cstyle = CStyleChecker (False)
|
|
cstyle.check_files (sys.argv [1:])
|
|
|
|
|
|
if cstyle.get_error_count ():
|
|
sys.exit (1)
|
|
|
|
sys.exit (0)
|