#! /bin/sh

# General style correction and cleanup.
t=__wt.$$
trap 'rm -f $t; exit 0' 0 1 2 3 13 15

cd ..

# Turn a C file into a line per function so we can use grep on it.
file_parse()
{
	sed -n \
	    -e '/^{$/,/^}$/{=;p;}' $1 |
	sed 'N;s/\n/:/' |
	sed -e '/./{H;/^[0-9][0-9]*:}$/!d;}' \
	    -e x \
	    -e 's/\n/ /g' \
	    -e p \
	    -e '{s/.*//;x;}'
}

# Returns in functions after a jump to the error label, or an infinite loop
# where there's a jump to the error label after the error label.
for f in `find bench examples ext src test -name '*.[ci]'`; do
	file_parse $f |
	egrep '(WT_ERR|WT_ERR_MSG|WT_ERR_NOTFOUND_OK|WT_ERR_TEST|WT_ILLEGAL_VALUE_ERR)\(.*(WT_ASSERT_RET|WT_ILLEGAL_VALUE|WT_RET|WT_RET_MSG|WT_RET_NOTFOUND_OK|WT_RET_TEST|WT_VERBOSE_RET|WT_VERBOSE_RETVAL)\(.*err:|[^a-z_]err:.*(WT_ERR|WT_ERR_MSG|WT_ERR_NOTFOUND_OK|WT_ERR_TEST|WT_ILLEGAL_VALUE_ERR)\(' |
	sed 's/:.*//' > $t

	test -s $t && {
		echo "$f: return after a jump to the error label or a jump to the error label after the error label"
		sed 's/^/function @ line:/' < $t
	}
done

# Return of 0 in functions after a jump to the error label.
for f in `find bench examples ext src test -name '*.[ci]'`; do
	file_parse $f |
	egrep -v '[^a-z_]err:.*return \(ret|[^a-z_]err:.*WT_RET' |
	egrep '[^a-z_]err:.*return \(0\);' |
	sed 's/:.*//' > $t

	test -s $t && {
		echo "$f: error label followed by a return of 0"
		sed 's/^/function @ line:/' < $t
	}
done

for f in \
    `find bench examples ext src test -name '*.[chisy]' -o -name '*.in' |
    sed -e '/Makefile.in/d' \
	-e '/build_win\/wiredtiger_config.h/d'`; do
	if grep "^[^}]*while (0);" $f > $t; then
		echo "$f: while (0) has trailing semi-colon"
		cat $t
	fi

	if grep "(unsigned)" $f > $t; then
		echo "$f: (unsigned) cast is wrong"
		cat $t
	fi

	if grep WT_DEADLOCK $f | grep -v '#define.WT_DEADLOCK' > $t; then
		echo "$f: WT_DEADLOCK deprecated in favor of WT_ROLLBACK"
		cat $t
	fi

	if ! expr "$f" : 'src/include/queue\.h' > /dev/null &&
	    egrep 'STAIL_|SLIST_|\bLIST_' $f ; then
		echo "$f: use TAILQ for all lists"
	fi

	if ! expr "$f" : 'src/os_posix/.*' > /dev/null &&
	   ! expr "$f" : 'src/os_win/.*' > /dev/null &&
	   ! expr "$f" : 'src/include/extern.h' > /dev/null &&
	   ! expr "$f" : 'src/include/os.h' > /dev/null &&
	   grep '__wt_errno' $f > $t; then
		echo "$f: upper-level code should not call __wt_errno"
		cat $t
	fi

	if ! expr "$f" : 'examples/c/.*' > /dev/null &&
	   ! expr "$f" : 'ext/datasources/helium/helium.c' > /dev/null &&
	   ! expr "$f" : 'src/include/os.h' > /dev/null &&
	    grep "%zu" $f | grep -v 'SIZET_FMT' > $t; then
		echo "$f: %zu needs to be fixed for Windows"
		cat $t
	fi

	egrep -w 'off_t' $f > $t
	test -s $t && {
		echo "$f: off_t type declaration, use wt_off_t"
		cat $t
	}

	# Direct calls to functions we're not supposed to use in the library.
	# We don't check for all of them, just a few of the common ones.
	if ! expr "$f" : 'bench/.*' > /dev/null &&
	   ! expr "$f" : 'examples/.*' > /dev/null &&
	   ! expr "$f" : 'ext/.*' > /dev/null &&
	   ! expr "$f" : 'test/.*' > /dev/null &&
	   ! expr "$f" : '.*/utilities/.*' > /dev/null; then
		if ! expr "$f" : '.*/os_alloc.c' > /dev/null &&
		     egrep '[[:space:]]free[(]|[[:space:]]strdup[(]|[[:space:]]strndup[(]|[[:space:]]malloc[(]|[[:space:]]calloc[(]|[[:space:]]realloc[(]' $f > $t; then
			test -s $t && {
				echo "$f: call to illegal function"
				cat $t
			}
		fi
		if ! expr "$f" : '.*/os_strtouq.c' > /dev/null &&
		     egrep '[[:space:]]strtouq[(]' $f > $t; then
			test -s $t && {
				echo "$f: call to illegal function"
				cat $t
			}
		fi
		if egrep '[[:space:]]exit[(]' $f > $t; then
			test -s $t && {
				echo "$f: call to illegal function"
				cat $t
			}
		fi
	fi

	# Declaration of an integer return variable.
	if ! expr "$f" : 'bench/.*' > /dev/null &&
	   ! expr "$f" : 'examples/.*' > /dev/null &&
	   ! expr "$f" : 'test/.*' > /dev/null &&
	   ! expr "$f" : 'ext/.*' > /dev/null; then
		egrep -w ret $f | egrep 'int.*[, ]ret[,;]' > $t
		test -s $t && {
			echo "$f: explicit declaration of \"ret\""
			cat $t
		}
	fi

	# Early exits from critical loops
	sed -n -e '/API_CALL.*;$/,/API_END.*;/{=;p;}' \
	       -e '/LSM_.*ENTER*;$/,/LSM_.*LEAVE*;/{=;p;}' \
	       -e '/va_start/,/va_end/{=;p;}' $f | \
		sed 'N;s/\n/:/' | \
		egrep -w 'return|WT_RET' | \
		sed -e "s,^,$f:," -e 's/$/ [return skips API_END call]/'

	tr -cd '[:alnum:][:space:][:punct:]' < $f |
	unexpand |
	sed -e 's/){/) {/' \
	    -e 's/\([	 ]\)for(/\1for (/' \
	    -e 's/\([	 ]\)if(/\1if (/' \
	    -e 's/\([	 ]\)index(/\1strchr(/' \
	    -e 's/\([	 ]\)return(/\1return (/' \
	    -e 's/\([	 ]\)return \([^()]*\);/\1return (\2);/' \
	    -e 's/\([	 ]\)rindex(/\1strrchr(/' \
	    -e 's/\([	 ]\)sizeof (/\1sizeof(/g' \
	    -e 's/\([	 ]\)switch(/\1switch (/' \
	    -e 's/\([	 ]\)while(/\1while (/' \
	    -e 's/\([	 ,]\)uint\([	 ,]\)/\1u_int\2/g' \
	    -e 's/\([	 ,]\)u_int8_t\([	 ,]\)/\1uint8_t\2/g' \
	    -e 's/\([	 ,]\)u_int16_t\([	 ,]\)/\1uint16_t\2/g' \
	    -e 's/\([	 ,]\)u_int32_t\([	 ,]\)/\1uint32_t\2/g' \
	    -e 's/\([	 ,]\)u_int64_t\([	 ,]\)/\1uint64_t\2/g' \
	    -e 's/\([	 ,]\)u_quad\([	 ,]\)/\1uint64_t\2/g' \
	    -e 's/\([|&=+-]\)  *\([^*]\)/\1 \2/' \
	    -e 's/(void) \([a-zA-Z_]\)/(void)\1/' \
	    -e '/for /!s/;;$/;/' \
	    -e 's/(EOPNOTSUPP)/(ENOTSUP)/' \
	    -e 's/(unsigned)/(u_int)/' \
	    -e 's/hazard reference/hazard pointer/' \
	    -e 's/^#define /#define	/' >$t

	cmp $t $f > /dev/null 2>&1 || (echo "modifying $f" && cp $t $f)
done

# Check Python coding standards: check for tab characters.
egrep '	' `find . -name '*.py'` |
    sed -e 's/:.*//' \
	-e '/__init__.py/d' \
	-e '/src\/docs\/tools\/doxypy.py/d' |
    sort -u |
    sed 's/^/	/' > $t
test -s $t && {
	echo '[tab] characters appear in Python scripts:'
	cat $t
}
# Check Python coding standards: check for trailing semi-colons.
# Don't check too widely, there are third-party tools that fail this test as
# well as scripts in this directory that output C code, and so fail the test.
egrep ';$' `find lang test -name '*.py'`> $t
test -s $t && {
	echo 'trailing semi-colons in selected Python code:'
	cat $t
}

# Check for common typos (Wikipedia's list).
find bench examples ext src test \
    -name '*.[chisy]' -o -name '*.in' -o -name '*.dox' |
xargs egrep -w 'a a|an an|and and|are are|be be|by by|for for|from from|if if|in in|is is|it it|of of|the the|this this|to to|was was|were were|when when|with with|a an|an a|a the|the a' > $t
	test -s $t && {
		echo "paired typo"
		echo "============================"
		cat $t
	}
