summaryrefslogtreecommitdiff
path: root/build-aux
diff options
context:
space:
mode:
authorJames Youngman <jay@gnu.org>2007-06-21 22:50:49 +0000
committerJames Youngman <jay@gnu.org>2007-06-21 22:50:49 +0000
commitc271e6e8b51a5941aad0574b39463e7c84076f75 (patch)
treee97f5f996e6e10fc442bc0d4303664e62fb92de4 /build-aux
parent76b2e5c5badeef24e79cc284162ab94ff170fc54 (diff)
downloadfindutils-c271e6e8b51a5941aad0574b39463e7c84076f75.tar.gz
Initial implementation of a source lint checker, mainly based on
Makefile.maint from coreutils.
Diffstat (limited to 'build-aux')
-rw-r--r--build-aux/src-sniff.py114
1 files changed, 114 insertions, 0 deletions
diff --git a/build-aux/src-sniff.py b/build-aux/src-sniff.py
new file mode 100644
index 00000000..9c9b7c91
--- /dev/null
+++ b/build-aux/src-sniff.py
@@ -0,0 +1,114 @@
+#! /usr/bin/env python
+
+
+import re
+import sys
+
+FIRST_INCLUDE = 'config.h'
+problems = 0
+
+LINE_SMELLS_SRC = [
+ [r'(?<!\w)free \(\(', "don't cast the argument to free()"],
+ [r'\*\) *x(m|c|re)alloc(?!\w)',"don't cast the result of x*alloc"],
+ [r'\*\) *alloca(?!\w)',"don't cast the result of alloca"],
+ [r'[ ] ',"found SPACE-TAB; remove the space"],
+ [r'(?<!\w)([fs]?scanf|ato([filq]|ll))(?!\w)',
+ 'do not use *scan''f, ato''f, ato''i, ato''l, ato''ll, ato''q, or ss''canf'],
+ [r'error \(EXIT_SUCCESS',"passing EXIT_SUCCESS to error is confusing"],
+ [r'file[s]ystem', "prefer writing 'file system' to 'filesystem'"],
+ [r'HAVE''_CONFIG_H', "Avoid checking HAVE_CONFIG_H"],
+ [r'HAVE_FCNTL_H', "Avoid checking HAVE_FCNTL_H"],
+ [r'O_NDELAY', "Avoid using O_NDELAY"],
+ [r'the *the', "'the the' is probably not deliberate"],
+ [r'(?<!\w)error \([^_"]*[^_]"[^"]*[a-z]{3}', "untranslated error message"],
+ [r'^# *if\s+defined *\(', "useless parentheses in '#if defined'"],
+
+ ]
+
+FILE_SMELLS_SRC = [
+ [r'# *include <assert.h>(?!.*assert \()',
+ "If you include <assert.h>, use assert()."],
+ [r'# *include "quotearg.h"(?!.*(?<!\w)quotearg(_[^ ]+)? \()',
+ "If you include \"quotearg.h\", use one of its functions."],
+ [r'# *include "quote.h"(?!.*(?<!\w)quote(_[^ ]+)? \()',
+ "If you include \"quote.h\", use one of its functions."],
+ [r'\s$', "trailing whitespace"],
+ ]
+
+# missing check: ChangeLog prefixes
+# missing: sc_always_defined_macros from coreutils
+# missing: sc_tight_scope
+
+COMPILED_LINE_SMELLS = [(re.compile(pong[0]), pong[1])
+ for pong in LINE_SMELLS_SRC]
+COMPILED_FILE_SMELLS = [(re.compile(pong[0], re.DOTALL), pong[1])
+ for pong in FILE_SMELLS_SRC]
+
+def Problem(filename, desc):
+ global problems
+ print >> sys.stderr, "error: %s: %s" % (filename, desc)
+ problems += 1
+
+def Warning(filename, desc):
+ print >> sys.stderr, "warning: %s: %s" % (filename, desc)
+
+
+def BuildIncludeList(text):
+ include_re = re.compile(r'# *include +[<"](.*)[>"]')
+ return [m.group(1) for m in include_re.finditer(text)]
+
+
+def CheckFirstInclude(filename, lines, fulltext):
+ includes = BuildIncludeList(fulltext)
+ if includes and includes[0] != FIRST_INCLUDE:
+ if FIRST_INCLUDE in includes:
+ fmt = "%s is first include file, but %s should be included first"
+ Problem(filename, fmt % (includes[0], FIRST_INCLUDE))
+ if FIRST_INCLUDE not in includes:
+ Warning(filename,
+ "%s should be included by most files" % FIRST_INCLUDE)
+
+def CheckLineSmells(filename, lines, fulltext):
+ for smell in COMPILED_LINE_SMELLS:
+ for line in lines:
+ match = smell[0].search(line[1])
+ if match:
+ Problem(filename, '%d: "%s": %s'
+ % (line[0], match.group(0), smell[1]))
+
+
+def CheckFileSmells(filename, lines, fulltext):
+ for smell in COMPILED_FILE_SMELLS:
+ match = smell[0].search(fulltext)
+ if match:
+ Problem(filename, ' %s'
+ % (smell[1],))
+
+
+
+
+def SniffSourceFile(filename, lines, fulltext):
+ for sniffer in [CheckFirstInclude, CheckLineSmells, CheckFileSmells]:
+ sniffer(filename, lines, fulltext)
+
+
+def main(args):
+ "main program"
+ for srcfile in args[1:]:
+ f = open(srcfile)
+ line_number = 1
+ lines = []
+ for line in f.readlines():
+ lines.append( (line_number, line) )
+ line_number += 1
+ fulltext = '\n'.join([line[1] for line in lines])
+ SniffSourceFile(srcfile, lines, fulltext)
+ f.close()
+ if problems:
+ return 1
+ else:
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main(sys.argv))