#! /bin/sh

# Check various WiredTiger function behaviors.
t=__wt.$$
trap 'rm -f $t' 0 1 2 3 13 15

fast=1
case "$1" in
    -F) # Run fast.
        fast=0
        shift;;
    *)
        if test $# -gt 1 ; then
            echo "Usage: $0 [-F]"
            echo "-F only run function validation on modified soure files."
        fi
        break;;
esac

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;}'
}

if test $fast -eq 1 ; then
    files=`find bench examples ext src test -name '*.c' -o -name '*_inline.h'`
else
    files=`git diff --name-only $(git merge-base --fork-point develop) bench examples ext src test | grep -E '(.c|_inline.h)$'`
fi

# 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 $files; do
    file_parse $f |
    egrep '(WT_ERR[_A-Z]*)\(.*(WT_RET[_A-Z]*)\(.*err:|[^a-z_]err:.*(WT_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

# Returns before jumps to an error label within the same loop.
# Jumps before returns have already been detected above.
for f in $files; do
    file_parse $f | sed "s=^=$f:="
done | python dist/s_function_loop.py |
    egrep '\{@[^@]*(WT_RET[_A-Z]*)\([^@]*(WT_ERR[_A-Z]*)\(.*err:' |
    sed -e 's/^\([^:]*\): *\([^:]*\):.*/\1:\2: mix of returns and jump to the error label within a loop/'

# Early exits from WT_WITH_* macros.
for f in $(grep -l 'WT_WITH_' $files); do
    echo "===$f==="
    cat $f
done | python dist/s_function_with.py 2>&1 $t || exit 1
test -s $t && {
    echo "Misuse of WT_WITH_* macros:"
    cat $t
}

# Return of 0 in functions after a jump to the error label.
for f in $files; 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

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

done

# API_END with a return
for f in $files; do
    file_parse $f |
    egrep '[^A-Z_]API_END.*return' |
    sed 's/:.*//' > $t
    test -s $t && {
        echo "$f: API_END followed by return."
        sed 's/^/function @ line:/' < $t
    }
done

# S2C with a local WT_CONNECTION_IMPL variable.
for f in $files; do
    file_parse $f |
    egrep 'conn = S2C.*S2C' |
    sed 's/:.*//' > $t
    test -s $t && {
        echo "$f: S2C with a local WT_CONNECTION_IMPL variable."
        sed 's/^/function @ line:/' < $t
    }
done

# S2B with a local WT_BTREE variable.
for f in $files; do
    file_parse $f |
    egrep 'btree = S2B.*S2B' |
    sed 's/:.*//' > $t
    test -s $t && {
        echo "$f: S2B with a local WT_BTREE variable."
        sed 's/^/function @ line:/' < $t
    }
done

if test $fast -eq 1 ; then
    files=`find src -name '*.c' -o -name '*._inline.h'`
else
    files=`git diff --name-only $(git merge-base --fork-point develop) src | grep -E '(.c|_inline.h)$'`
fi

# __wt_verbose with a bitwise OR category parameter.
for f in $files; do
    file_parse $f | python dist/s_function_verbose.py > $t
    test -s $t && {
        echo "$f: Invalid use of verbose category parameter (bitwise OR)."
        sed 's/^/function @ line:/' < $t
    }
done

exit 0
