| #!/usr/bin/env bash |
| # |
| # usage: inclosure [ -I dir ] ... [ -G header-name ] ... header-name ... |
| # |
| # Locates each standard header and argument header-name in the |
| # specified "-I" include path (default is /usr/include) and parses |
| # any header names out of its #include directives. These names are |
| # treated recursively to identify a _transitive_closure_ of standard |
| # header names, which is sorted and sent to standard output. Headers |
| # not specified with -G, and included somewhere but not located are |
| # reported. |
| # |
| # Each header reported by this program must be "shadowed" by a |
| # file of the same name in a C++ header. See |
| # http://www.cantrip.org/cheaders.html |
| # |
| # BUGS: |
| # - Cannot cope with header file names that contain spaces |
| # - Ignores comment-block delimiters |
| # - Ignores sub-includes under #include_next headers. |
| |
| OLDH=/tmp/old$$ |
| echo "this-compensates-for-a-stupid-bug-in-GNU-fgrep." >$OLDH |
| HDRS=/tmp/hdrs$$ |
| >$HDRS |
| NEW=/tmp/new$$ |
| >$NEW |
| IGNORES=/tmp/ignores$$ |
| echo "this-compensates-for-a-stupid-bug-in-GNU-fgrep.">$IGNORES |
| |
| trap "rm -f $NEW $HDRS $OLDH $IGNORES" 0 |
| |
| # process arguments |
| unset INCPATH |
| while [ $# != 0 -a "$1" != "${1#-}" ]; do |
| FLAG="${1%%${1##-?}}" |
| case "$FLAG" in -I|-G) |
| ARG="${1##${FLAG}}" |
| if [ "$ARG" = "" ]; then |
| if [ $# != 0 ]; then |
| shift; |
| ARG="$1" |
| else |
| echo "$0: $FLAG needs an argument." |
| exit |
| fi |
| fi ;; |
| esac |
| shift |
| case "$FLAG" in |
| -I) INCPATH="$INCPATH $ARG" ;; |
| -G) echo " $ARG " >>$IGNORES ;; |
| esac |
| done |
| INCPATH=${INCPATH-"/usr/include"} |
| |
| # identify headers |
| |
| STDHDRS="assert.h ctype.h errno.h float.h limits.h \ |
| locale.h math.h setjmp.h signal.h stdarg.h stddef.h \ |
| stdio.h stdlib.h string.h time.h wchar.h wctype.h " |
| OTHERS="$*" |
| |
| for file in $STDHDRS $OTHERS; do |
| echo "$file" |
| done >$HDRS |
| |
| until cmp -s $OLDH $HDRS; do # (until no new headers found) |
| |
| fgrep -v -f $OLDH $HDRS \ |
| | while read file; do |
| found=no |
| for dir in $INCPATH; do |
| name="$dir/$file" |
| if [ -f "$name" ]; then |
| cat "$name" |
| found=yes |
| break; |
| fi |
| done |
| if [ "$found" = no ]; then # && echo " $file " | fgrep -v -q -f $IGNORES |
| echo "$0: warning: header $file not found in include path." $1>&2 |
| fi |
| done \ |
| | sed -n -e \ |
| '/^[ ]*#[ ]*include[ ]*<[^>]*>/s/^[^<]*<\([^>]*\)>.*/\1/p' \ |
| | while read file; do |
| drop=no |
| for ignore in `cat $IGNORES`; do |
| if [ "$ignore" = "$file" ]; then drop=yes; fi |
| done |
| case "$file" in /*) drop=yes;; esac # no absolute paths |
| case $drop in no) echo "$file";; esac |
| done >$NEW |
| mv $HDRS $OLDH |
| cat $OLDH $NEW | sort -u -o $HDRS |
| |
| done |
| cat $HDRS |
| |
| |
| |