#! /bin/sh # Ensure consistent style by catching common improper constructs. set -e diag() { fail=: echo "$file:" "$@" echo ============================================================ } rm -f failures # Get some help from GNU grep. if (grep --color=auto -n --version)>/dev/null 2>&1; then GREP_OPTIONS='--color=auto -n' GREP_COLOR='1;31' export GREP_OPTIONS export GREP_COLOR fi # Reset the locale, so for instance we don't get bugs because sed is # expecting utf-8 and we feed him latin-1. The C locale should be OK, # because we do not treat extended characters specifically in the # following style rules. LC_ALL=C export LC_ALL tmp=incltest.tmp for dir in "${INCDIR-..}" "${INCDIR-..}"/../iface; do find "$dir" \( -name "${1-*}.hh" \ -o -name "${1-*}.hxx" \ -o -name "${1-*}.cc" \ -o -name "${1-*}.test" \) \ -a -type f -a -print | while read file; do if grep 'GNU Bison' "$file" >/dev/null || grep 'generated by flex' "$file" >/dev/null ; then continue fi # Skip the files used by sanity. case $file in *incltest.cc) continue;; esac fail=false # Check this before stripping comments and strings. grep -i 'accepting cond' $file && diag 'accepting -> acceptance' grep Copyright $file >/dev/null || diag "missing copyright" # Strip comments and strings. sed 's,[ ]*//.*,,;s,"[^"]*","",g' < $file > $tmp grep '[ ]$' $tmp && diag 'Trailing whitespace.' case $file in *.test);; *) grep -E '[^<]class[ \t]+[A-Z]' $tmp && diag 'Use lower case class names.' grep '[ ]if(' $tmp && diag 'Missing space after "if"' grep '[ ]if (.*).*{' $tmp && diag 'Opening { should be on its own line.' grep '[ ]if (.*).*;' $tmp && diag 'if body should be on another line.' grep '[ ]else.*;' $tmp && diag 'else body should be on another line.' grep '[ ]while(' $tmp && diag 'Missing space after "while"' grep '[ ]while (.*).*{' $tmp && diag 'Opening { should be on its own line.' grep '[ ]while (.*).*[^)];' $tmp && diag 'while body should be on another line.' grep '[ ]for(' $tmp && diag 'Missing space after "for"' grep '[ ]for (.*).*{' $tmp && diag 'Opening { should be on its own line.' grep '[ ]for (.*;.*;.*).*;' $tmp && diag 'for body should be on another line.' grep '[ ]switch(' $tmp && diag 'Missing space after "switch"' grep '[ ]switch (.*).*{' $tmp && diag 'Opening { should be on its own line.' grep 'namespace .*{' $tmp && diag 'Opening { should be on its own line.' grep 'class .*{' $tmp && diag 'Opening { should be on its own line.' grep '( ' $tmp && diag 'No space after opening (.' grep ' )' $tmp && diag 'No space before closing ).' grep '! ' $tmp && diag 'No space after unary operators (!).' grep ",[^ \" %'\\\\]" $tmp && diag 'Space after coma.' # The 'r' allows operator&& grep '[^ r]&&[^ ]' $tmp && diag 'Space arround binary operators.' # The 'r' allows operator|| grep '[^ r]||[^ ]' $tmp && diag 'Space arround binary operators.' # The 'r' allows operator== grep '[^ r][!<>=]=[^ ]' $tmp && diag 'Space arround binary operators.' grep '[ ]default:[^:].*;' $tmp && diag 'Label should be on their own line.' grep '[ ]case.*:[^:].*;' $tmp && diag 'Label should be on their own line.' grep '[ ];' $tmp && diag 'No space before semicolon.' grep -v 'for (.*;;)' $tmp | grep ';[^ ")]' && diag 'Must have space or newline after semicolon.' grep '}.*}' $tmp && diag 'No two } on the same line.' grep '{.*{' $tmp && diag 'No two { on the same line.' grep 'delete[ ]*[(][^(]*[)];' $tmp && diag 'No useless parentheses after delete.' grep 'return[ ]*[(][^(]*[)];' $tmp && diag 'No useless parentheses after return.' grep 'NULL' $tmp && diag 'Use 0 instead of NULL. NULL is not portable.' # std::list::size() can be O(n). Better use empty() whenever # possible, even for other containers. egrep '(->|[.])size\(\) [=!]= 0|![a-zA-Z0-9_]*(->|[.])size\(\)|(if |while |assert)\([a-zA-Z0-9_]*(->|[.])size\(\)\)' $tmp && diag 'Prefer empty() to check emptiness.' egrep '^[^=*<]*([+][+]|--);' $tmp && diag 'Take good habits: use ++i instead of i++ when you have the choice.' grep '[^a-zA-Z0-9_](\*[a-zA-Z0-9_]*)\.' $tmp && diag 'Use "x->y", not "(*x).y"' grep 'std::hash' $tmp && diag 'use Sgi:: for hash and hash_map' grep 'Sgi::[^h]' $tmp && diag 'Sgi:: is for hash and hash_map only' egrep 'bdd_(false|true)[ ]*\(' $tmp && diag 'Use bddfalse and bddtrue instead of bdd_false() and bdd_true()' res=`perl -ne '$/ = undef; print "$&\n" while /if \((.*)(\s*==\s*0)?\)\s*delete(\[\])?\s+\1;(?!\s+else)/g' $tmp` if test -n "$res"; then echo "$res" diag 'No "if (x)" required before "delete x;".' fi case $file in *.hh | *.hxx) if egrep '(cout|cerr|clog)' $tmp >/dev/null; then : else grep '#.*include.*' $tmp && diag 'Avoid in headers, better use .' fi ;; *.cc) if grep 'namespace$' $tmp >/dev/null; then : else # We only check classes, but the rule should apply to functions too grep '^[ ]*class[ ]' $tmp && diag 'Private definitions must be in anonymous namespace.' fi ;; esac ;; esac $fail && echo "$file" >>failures done || : # Make sure sh does not abort when read exits with false. done # Rules for Makefiles. for dir in "${INCDIR-..}" "${INCDIR-..}"/../iface; do find "$dir" -name "Makefile.am" -a -type f -a -print | while read file; do fail=false # Strip comments. sed 's,#.*,,' < $file > $tmp grep '[ ]$' $tmp && diag 'Trailing whitespace.' grep '\.libs/' $tmp && diag "Don't reference files in .libs/, use Libtool instead." $fail && echo "$file" >>failures done || : # Make sure sh does not abort when read exits with false. done if test -f failures; then echo "The following files contain style errors:" cat failures rm failures exit 1; fi exit 0