#! /bin/sh
#
# makedep - Constructs dependency lines for makefiles.
#
# Synopsis
#	makedep [options] [directories]
#
# Discussion
#   Makedep constructs a makefile-style dependency list
#   showing which header files the object files constructed
#   from the source files in the given directories depend
#   upon.  The dependency of the object file upon the source 
#   file is not indicated in the output; this dependency can 
#   usually be inferred by the make program.
#
#   If no directories are given, the default is to look in the
#   current directory.  Directory names here and in the -I
#   option may be given relative to the directory from which
#   makedep is invoked.  
#
#   Makedep handles nested includes properly, propagating
#   dependencies of one header file upon another back to
#   each object file whose source file includes the dependent
#   header file.
#
# Options
#   -o outfile
#	Output file name.  Default is "dependencies".
#   -I dir
#	Add "dir" to the include file search list.  Multiple
#	-I options accumulate, building the search list from
#	left to right, with the system include directories 
#	added at the end.  The space separating the directory
#	name from the -I may be omitted.
#   -x
#	Add the V-System experimental include directory to
#	the beginning of the system include directory search
#	list.  Should be used if the source files are to be
#	compiled with the -vx switch of cc68.
#   -u
#	Use a set of system include directories and default
#	extensions appropriate to Vax/Unix. The default is
#	to use Sun/V conventions.
#   -s
#	Suppress dependencies on files in the standard system
#	include directories.  Only dependencies on files
#	found in (or relative to) source directories or 
#	directories given in -I options will appear in the
#	output.  This option also suppresses the warning
#	message ordinarily printed when a header file cannot
#	be found.
#   -S ext
#	Source files have extension ".ext", default ".c".
#   -O ext
#	Object files have extension ".ext", default ".b".  The
#	-u option changes this option to ".o", so -O should 
#	appear after -u if both are given.
#
# Bugs
#   Incredibly slow for large sets of files.  Should be
#   rewritten in C.
#
# Author
#   Tim Mann, Feb 11, 1984
#

# default extensions for source, object
srcext=c
objext=b

# default source directory list
srcdirs="."

# default search lists for include files
incldirs="/usr/sun/include /usr/local/include /usr/include"
xincldirs="/usr/sun/xinclude"
unixincldirs="/usr/include"
userincldirs=""

# default output file name
out="dependencies"

# Parse command line options
sflag=""
uflag=""
xflag=""
moreoptions=1
while [ $moreoptions ]
    do
    case $1 in
        -o)
	    # Output file name
	    out=$2
	    shift
	    shift
	    ;;
	-o*)
	    # Output file name -- space omitted
	    out=`echo $1 | sed 's/-.\(.*\)/\1/'`
	    shift
	    ;;
	-I)
	    # Add to include directory search list
	    userincldirs="$userincldirs $2"
	    shift
	    shift
	    ;;
	-I*)
	    # Like -I, with space omitted
	    userincldirs="$userincldirs `echo $1 | sed 's/-.\(.*\)/\1/'`"
	    shift
	    ;;
	-x)
	    # Add V experimental include directory
	    incldirs="$xincldirs $incldirs"
	    xflag=1
	    shift
	    ;;
	-u)
	    # Use only Unix include directory
	    incldirs=$unixincldirs
	    objext=o
	    uflag=1
	    shift
	    ;;
	-s)
	    # Suppress dependencies on system standard include files
	    incldirs=""
	    sflag=1
	    shift
	    ;;
	-S)
	    # Set source extension
	    srcext=$2
	    shift
	    shift
	    ;;
	-S*)
	    srcext=`echo $1 | sed 's/-.\(.*\)/\1/'`
	    shift
	    ;;
	-O)
	    # Set object extension
	    objext=$2
	    shift
	    shift
	    ;;
	-O*)
	    srcext=`echo $1 | sed 's/-.\(.*\)/\1/'`
	    shift
	    ;;
	-*)
	    echo 1>&2 ${0}: Unknown switch $1
	    exit 1
	    ;;
        *)
	    moreoptions=""
	    ;;
        esac
    done

if [ 0$uflag$sflag$xflag = 011 -o 0$uflag$sflag$xflag = 0111 ]
    then
    echo 1>&2 ${0}: -u, -s, and -x are mutually exclusive.
    exit 1
    fi

# Source directories specified?
if [ $# -gt 0 ]
    then
    srcdirs=$*
    fi

incldirs="$userincldirs $incldirs LAST"

cwd=`pwd`
tmpa=/tmp/makedep$$a
tmpb=/tmp/makedep$$b
trap "rm -f $tmpa $tmpb; exit 1" 1 2 13 15  #clean up on abnormal exits

for dir in $srcdirs
    do
    cd $dir
#
# First, find each #include and chop out all but the
#   filename with sed.  Pass on the name of the source
#   file with its extension changed to OBJEXT, and the
#   name of the included file.  Also pass on $dir if the
#   name was enclosed in "" rather than <>, indicating
#   that the directory containing the file should be 
#   searched first.
#
    for file in *.$srcext
	do
        sed "s|^#[ 	]*include.*<\(.*\)>.*$|$file: \1|
s|^#[ 	]*include.*\"\(.*\)\".*$|$file: \1 $dir|
t found
d
b
: found
s|\.$srcext:|.$objext:|
t" $file | \
        (
#
# Next, find the name of the directory containing each
#   .h file and prepend it.
#
	    cd $cwd
	    while read obj hdr firstdir
		do
		case $hdr in
		    /*)
			# Absolute pathname -- nothing to do
			echo $obj $hdr		    
			;;
		    *)
			for incldir in $firstdir $incldirs
			    do
			    if [ -s $incldir/$hdr ]
				then
				echo $obj $incldir/$hdr
				break
				fi
			    done
			if [ $incldir = LAST -a ! "$sflag" ]
			    then
			    echo 1>&2 ${0}: $obj $hdr --include file not found
			    fi
			;;
		    esac
		done
        )	
	done
    cd $cwd
    done | \
sort -t: >$tmpb
echo -n >$tmpa	#make $tmpa empty
#
# Now we want to add in the dependencies caused by nested
#   includes and compute the transitive closure.
#
until cmp -s $tmpa $tmpb
    do
    mv $tmpb $tmpa
    while read obj hdr		#from $tmpa to $tmpb
         do
#
# First, find each #include in a header file
#   and chop out all but the file name with sed.  Also
#   pass on the name of the directory in which the header
#   file itself is stored if the included file's name is
#   given in "" marks rather than <>.
#
        echo $obj $hdr
	sed "s|^#[ 	]*include.*\"\(.*\)\".*$|\1 %$hdr|
s|^#[ 	]*include.*<\(.*\)>.*$|\1|
t found
d
b
: found
s|%\(.*\)/.*|\1|
t" $hdr | \
        (
#
# Next, find the name of the directory containing each
#   .h file and prepend it.
#
	    while read subhdr hdrdir
	        do
		case $subhdr in
		    /*)
			# Absolute pathname
			echo $obj $subhdr
			;;
		    *)
		        for incldir in $hdrdir $incldirs
			    do
			    if [ -s $incldir/$subhdr ]
			        then
			        echo $obj $incldir/$subhdr
			        break
			        fi
			    done
		        if [ $incldir = LAST -a ! "$sflag" ]
			    then
			    echo 1>&2 ${0}: $obj $subhdr --include file not found
			    fi
			;;
		    esac
		done
         ) 
        done <$tmpa | \
    sort -t: | \
    uniq >$tmpb
    done
#
# Finally, use awk to gather all the dependencies for a given
#   object file into one line
#
awk <$tmpb >$out 'BEGIN { ORS=" "; nl="" }
{ if ( $1 != prev ) { print nl $0; prev = $1; nl="\n" } 
		else print $2 }'
echo >>$out  #terminate file with a newline
rm -f $tmpa $tmpb
