1# A bunch of shell functions that help finding unnecessary includes.
2# Relies on appropriate versions of etags, grep, tr, awk and maybe bash.
3#
4# To use:
5#   $ . util/includes.sh
6#   $ checkall
7
8# Tries to list all names defined in the header file $1.
9# Indented names are assumed to be members that don't need to be checked,
10# which will fail for indented declarations with #ifdefs.
11_wrap_etags()
12{
13    tmp=$1.etags.h
14    # clean up const member functions since they confuse etags
15    sed -e 's/) const\;/)\;/' < $1 > $tmp
16    etags --declarations $tmp -o -
17    rm $tmp
18}
19
20names ()
21{
22    b=$(basename $1 .h);
23    {
24        _wrap_etags $1 \
25            | grep '\(^[#a-z]\|^ *[0-9A-Z_][0-9A-Z_][0-9A-Z_]\)' \
26            | grep -v '^'$b'\.h' \
27            | tr '\177' '\t' | awk '{ print $(NF-1) }' \
28        # etags misses namespace declarations
29        grep namespace $1 | awk '{ print $NF }'
30        # and some function definitions...
31        grep '^[a-z]' $1 | grep '(' | cut -d'(' -f 1 | awk '{ print $NF }'
32    } | sed -e 's/^\**//;s/[^a-zA-Z0-9]$//' | sort | uniq
33}
34
35# lists possible uses in $2 of names defined in $1
36mightuse ()
37{
38    for n in $(names $1);
39    do
40        if grep -F $n $2; then
41            return 0;
42        fi;
43    done;
44    return 1
45}
46
47# checks whether source file $2 #include's $1
48includes ()
49{
50    grep '#include "'$1'"' $2
51}
52
53# echo arguments if $2 includes $1 put shouldn't
54check ()
55{
56    if includes $1 $2 > /dev/null && ! mightuse $1 $2 > /dev/null; then
57        echo $1 $2;
58    fi
59}
60
61# run check on all source for a given header
62# should really cache the result of "names"
63checkhdr ()
64{
65    for src in *.cc; do
66        check $1 $src
67    done
68}
69
70# Run check on all headers for a given source
71# This is useful when you just want to check a single source file, most
72# likely because that source file has recently been heavily modified.
73checkcc ()
74{
75    for hdr in *.h; do
76        check $hdr $1
77    done
78}
79
80# run check on all pairs
81checkall ()
82{
83    checkafter ""
84}
85
86# Run checkhdr on all pairs alphabetically after a specific header
87# Useful to run directly in the case running checkall is interrupted.
88checkafter ()
89{
90    for hdr in *.h; do
91        if [[ $hdr < $1 || $hdr = AppHdr.h ]]; then
92            continue;
93        fi
94
95        checkhdr $hdr
96    done
97}
98
99# remove #include of $1 from $2
100remove ()
101{
102    b=$(basename $1 .h)
103    re='^#include "'$b'\.h"$'
104    if grep "$re" $2 > /dev/null; then
105        sed -e '/^#include "'$b'\.h"$/d' < $2 > $2.rmincl
106        mv $2.rmincl $2
107    fi
108}
109
110# remove doubtful includes for a list as output by checkall.
111removelst ()
112{
113    while read hdr src; do
114        remove $hdr $src
115    done
116}
117
118# remove special includes
119cleanup ()
120{
121    sed -e '/^quiver.h/d;
122            /^ghost.h kills.cc$/d;
123            /^cmd-name.h macro.cc$/d;
124            /^cmd-keys.h macro.cc$/d;
125            /^mon-spell.h monster.cc$/d;
126            /^AppHdr.h /d;
127            / artefact.cc/d'
128}
129