#!/bin/bash

# Check various WiredTiger function behaviors.
. `dirname -- ${BASH_SOURCE[0]}`/common_functions.sh
setup_trap
cd_top
check_fast_mode_flag

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

# Parallel execution: if it's the main onvocation of the script, collect the file names
# to process and run them in subprocesses.
is_main_run && {
    find bench examples ext src test tools/checksum_bitflip -name '*.c' -o -name '*_inline.h' |
    do_in_parallel
    exit $?
}

# A list of files provided: process them one by one.

for f in "$@"; do
    fp="$(file_parse $f)"

    # 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.
    {
        echo "$fp" |
        grep -E '(WT_ERR[_A-Z]*)\(.*(WT_RET[_A-Z]*)\(.*err:|[^a-z_]err:.*(WT_ERR)\(' |
        sed 's/:.*//' > $t-1

        test -s $t-1 && {
            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-1
        }
    }

    # Returns before jumps to an error label within the same loop.
    # Jumps before returns have already been detected above.
    {
        echo "$fp" |
        sed "s=^=$f:=" |
        python3 dist/s_function_loop.py |
            grep -E '\{@[^@]*(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.
    grep -q 'WT_WITH_' $f && {
        {
            echo "===$f==="
            cat $f
        } | python3 dist/s_function_with.py 2>&1 $t-2 || exit 1
        test -s $t-2 && {
            echo "Misuse of WT_WITH_* macros:"
            cat $t-2
        }
    }

    # Return of 0 in functions after a jump to the error label.
    {
        echo "$fp" |
        grep -E -v '[^a-z_]err:.*return \(ret|[^a-z_]err:.*WT_RET' |
        grep -E '[^a-z_]err:.*return \(0\);' |
        sed 's/:.*//' > $t-3

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

    # Early exits from critical loops.
    {
        echo "$fp" 2>/dev/null |
        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/:/' | \
            grep -E -w 'return;|return \(|WT_RET' | \
            sed -e "s,^,$f:," -e 's/$/ [return skips matching end call]/'
    }

    # API_END with a return
    {
        echo "$fp" |
        grep -E '[^A-Z_]API_END.*return' |
        sed 's/:.*//' > $t-4
        test -s $t-4 && {
            echo "$f: API_END followed by return."
            sed 's/^/function @ line:/' < $t-4
        }
    }

    # S2C with a local WT_CONNECTION_IMPL variable.
    {
        echo "$fp" |
        grep -E 'conn = S2C.*S2C' |
        sed 's/:.*//' > $t-5
        test -s $t-5 && {
            echo "$f: S2C with a local WT_CONNECTION_IMPL variable."
            sed 's/^/function @ line:/' < $t-5
        }
    }

    # S2B with a local WT_BTREE variable.
    {
        echo "$fp" |
        grep -E 'btree = S2B.*S2B' |
        sed 's/:.*//' > $t-6
        test -s $t-6 && {
            echo "$f: S2B with a local WT_BTREE variable."
            sed 's/^/function @ line:/' < $t-6
        }
    }

    # __wt_verbose with a bitwise OR category parameter.
    [[ "$f" =~ (\.c|\._inline\.h)$ ]] && {
        echo "$fp" | python3 dist/s_function_verbose.py > $t-7
        test -s $t-7 && {
            echo "$f: Invalid use of verbose category parameter (bitwise OR)."
            sed 's/^/function @ line:/' < $t-7
        }
    }

    # WT_STRING_MATCH or WT_CONFIG_MATCH with a literal string.
    {
        echo "$fp" |
        grep -E 'WT_(STRING|CONFIG)_MATCH *\( *"' |
        sed 's/:.*//' > $t-8
        test -s $t-8 && {
            echo "$f: WT_{STRING|CONFIG}_MATCH used with a literal string," \
                "use WT_{STRING|CONFIG}_LIT_MATCH."
            sed 's/^/function @ line:/' < $t-8
        }
    }

    wait
done

exit 0
