#!/bin/ksh
#      *********************************************************
#      *                                                       *
#      *        Tree Source Compilation and Maintenance        *
#      *                                                       *
#      *********************************************************
#      File: utils/misc/compall
#
#        COPYRIGHT (c) 1993, 1995, 1996, 1999, 2000, 2002  BY
#         SIGMET INCORPORATED, WESTFORD MASSACHUSETTS, U.S.A.
# 
# THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
# ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
# INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
# COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
# OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
# TRANSFERED.

RUNROOT="`pwd`"
TMPFULL="/tmp/$$_tmpfull" ; TMPFIRST="/tmp/$$_tmpfirst"
TMPMAKE="/tmp/$$_tmpmake" ; TMP="/tmp/$$_tmp"

trap 'rm -f ${TMP} ${TMPFULL} ${TMPFIRST} ${TMPMAKE} ${LOCKFILE} ; exit' INT EXIT
rm -f ${TMP} ${TMPFULL} ${TMPFIRST} ${TMPMAKE}

# ==================================================
# Function to help rearrange the list of directories to process
#
changeOrder() {
  grep    "$1" ${TMPFULL} >> ${TMPFIRST}
  grep -v "$1" ${TMPFULL} >> ${TMP} ; mv ${TMP} ${TMPFULL}
}

# ==================================================
# Stop filter of directories not to bother searching (or which must
# not be searched).  Do not traverse the hardware directory on HAZE,
# as it contains makefiles which ought not be rerun frivolously.
#
STOPPATTERNS="-e sigmet/RCS       \
              -e sigmet/RCS_ref   \
              -e sigmet/bin       \
              -e sigmet/custom    \
              -e sigmet/info      \
              -e sigmet/manuals   \
              -e sigmet/release   \
                                  "
if [ "`hostname`" = "haze" ] ; then
  STOPPATTERNS="${STOPPATTERNS} -e sigmet/hardware"
fi

alias STOPFILTER="egrep -v ${STOPPATTERNS}"

# --------------------------------------------------
# Extract args that are to be passed on to makefile, and those which
# are immediately for us.
#
VERBOSE="" ; LOCALCMD="" ; NODEPEND="" ; MAKEFILE="Makefile" ; MAKEOPTS=""

while [ ! "$1" = "" ] ; do
  OPT="$1" ; shift

  if [ "${OPT}" = "-v" ] ; then
    VERBOSE="true"

  elif [  "${OPT}" = "-nodepend" ] ; then
    MAKEFILE=${TMPMAKE} ; NODEPEND="true"

  elif [  "${OPT}" =  "help"  -o \
          "${OPT}" = "-help"  ] ; then
    echo "Compall Options & BuiltIn Commands:"
    echo "          -v : Verbose output"
    echo "   -nodepend : Carry out operations, but ignore dependencies"
    echo "    checkexe : Check for executables that are older than libraries"
    echo "   checkmake : Perform consistency checks on Makefiles"
    echo
    echo "All other args are passed on to the Makefile"
    echo
    exit 0

  elif [  "${OPT}" = "checkexe"     -o \
          "${OPT}" = "checkinc"     -o \
          "${OPT}" = "checkmake"     ] ; then
    LOCALCMD=${OPT}

  else
    if [ "${MAKEOPTS}" = "" ] ; then  MAKEOPTS=${OPT}
                                else  MAKEOPTS="${MAKEOPTS} ${OPT}"
    fi
  fi
done

if [ "${MAKEOPTS}" = "clean"     -o \
     "${MAKEOPTS}" = "cleanexe"   ] ; then
    NODEPEND="true"
fi

# --------------------------------------------------
# Make a listing of the full path names of all directories.  Filter
# directories that are never supposed to be searched.  Then rearrange
# so that libraries, if any, are done first.
#
find ${RUNROOT} -type d -print | STOPFILTER | sort -u > ${TMPFULL}

changeOrder "/libs/user"
changeOrder "/libs/config"
changeOrder "/libs/xpm"
changeOrder "/libs/"
changeOrder "/iris/misc"
changeOrder "/iris/outlib"
changeOrder "/iris/share"
changeOrder "/iris/xsig"
changeOrder "/hardware/rimioapi"
changeOrder "/rda/intelipp"
changeOrder "/rda/rdasubs"
changeOrder "/rda/pcicards"
changeOrder "/rda/softplane"
changeOrder "/rda/rvp8main/core"
changeOrder "/rda/rvp8main/site"
changeOrder "/rda/rvp8proc/core"
changeOrder "/rda/rvp8proc/site"
changeOrder "/rda/rcp8/core"
changeOrder "/rda/rcp8/site"
changeOrder "/ts/archlib"

# --------------------------------------------------
# Do a first pass check on whether anyone else is obviously compiling
# in any of the directories that we will eventually hit.  This is a
# fatal error if found, but passing this test does not guarantee that
# we will not encounter problems later.
#
for WHERE in `cat ${TMPFIRST}` `cat ${TMPFULL}` ; do
  LOCKFILE="${WHERE}/compall_lock"
  if [ -r ${LOCKFILE} ] ; then
    OTHERUSER="`cat ${LOCKFILE} 2>&-`"
    echo "Sorry, '${OTHERUSER}' is compiling in ${WHERE}"

    # The following error exit first removes the definition of
    # LOCKFILE so that the exit handler does not delete the other
    # users lock!
    #
    LOCKFILE="" ; exit 1
  fi
done

# --------------------------------------------------
# Now execute each one...
#
INCERRGREP="" ; LIBFILES=""
for WHERE in `cat ${TMPFIRST}` `cat ${TMPFULL}` ; do

  cd ${WHERE}
  if [ -r "Makefile" ] ; then

    # If someone else is compiling in this directory, then signal that
    # it is busy and proceed no further.  We need to test again here,
    # even though the initial test had already looked here earlier.
    # Conflicts here are not fatal, but skip the directory at hand.
    #
    LOCKFILE="${WHERE}/compall_lock"
    if [ -r ${LOCKFILE} ] ; then
      OTHERUSER="`cat ${LOCKFILE} 2>&-`"
      echo "Sorry, '${OTHERUSER}' is compiling in ${WHERE}"

    else
      echo "${LOGNAME}" > ${LOCKFILE}

      # If a copied and modified version of the Makefile is needed,
      # then create that file now.
      #
      if [ "${MAKEFILE}" = "${TMPMAKE}" ] ; then
        rm -f ${MAKEFILE}
        egrep -v '^[0-9a-zA-Z_]*.o[ 	]*:[ 	]*[0-9a-zA-Z_]*.[cC][ 	]*;' \
          Makefile  > ${MAKEFILE}
        echo ".SUFFIXES :"    >> ${MAKEFILE}
        echo ".SUFFIXES : .o" >> ${MAKEFILE}
      fi

      # --------------- Check necessity of running cleanexe ---------------
      #
      if [ "${LOCALCMD}" = "checkexe" ] ; then

        if [ "${WHERE%%*/utils/local}"    != "" -a \
             "${WHERE%%*/libs/antenna}"   != "" -a \
             "${WHERE%%*/libs/user}"      != "" -a \
             "${WHERE%%*/iris/misc}"      != "" ] ; then

          echo "Checking executables in ${WHERE} ..."

          # Make up fixed list of library files to be considered.  Do
          # this only once, since it does not change.
	  #
          if [ "${LIBFILES}" = "" ] ; then
            LIBFILES=`find ${RUNROOT} -name "*.a" -print`
          fi

          # Make up a list of executable files in the current
          # directory.  Then look for any such file that is older than
          # any of the libraries.
	  #
          EXES=""
          for FILE in * ; do
            if [ -x ${FILE} ] ; then EXES="${EXES} ${FILE}" ; fi
          done

          rm -f ${TMP} ; cat /dev/null > ${TMP}
          if [ ! "${EXES}" = "" ] ; then
            for FILE in ${LIBFILES} ; do
              find ${EXES} ! -newer ${FILE} -print >> ${TMP}
            done
            sort -u < ${TMP} | pr -r -t -o2 ; rm -f ${TMP}
          fi
        fi

      # --------------- Check Makefile Sources ---------------
      #
      elif [ "${LOCALCMD}" = "checkmake" ] ; then
        echo "Checking Makefile in ${WHERE} ..."

        # Scan the Makefile and extract all file names that end in
        # '.c', '.C'.  Then verify that all such files exist in the
        # directory.  Remove lines that seem to be deleting temporary
        # intermediate files.
        #
        STOPSRCS="build_date.c" # (egrep format)
	SOURCES="`egrep -v '^[ 	]*#|rm -f' ${MAKEFILE} |
                  tr -sc '[0-9a-zA-Z]_\.' '[\012*]' |
                  sort -u | egrep '[0-9a-zA-Z]+\.[cC]' |
                  egrep -v \"${STOPSRCS}\"`"

        for FILE in ${SOURCES} ; do
          if [ ! -r ${FILE} ] ; then
            echo "  Referenced file that does not exist: '${FILE}'"
          fi
        done

	# Verify that every '.c' and '.C' file that has an include
	# statement appears somewhere in the dependencies at the end
	# of the Makefile.  Do this only if the source file itself is
	# actually referenced in the Makefile.  This gives some
	# confidence that all of the dependencies for that source file
	# are being checked.
	#
	SOURCES="`egrep -l '^[	 ]*#include' *.[cC] 2>&-`"

        for FILE in ${SOURCES} ; do
	  BNAME="${FILE%.[cC]}" ; OFILE="${BNAME}.o"
	  egrep "^[ 	]*${OFILE}[ 	]*:" ${MAKEFILE} > /dev/null 2>&-
          if [ "$?" != "0" ] ; then
	    egrep "${BNAME}" ${MAKEFILE} > /dev/null 2>&-
            if [ "$?" = "0" ] ; then
              echo "  Missing dependency for: '${FILE}'"
	    fi
          fi
        done

      # --------------- Check Include Syntax in Sources ---------------
      #
      elif [ "${LOCALCMD}" = "checkinc" ] ; then
        echo "Checking <>/\"\" include syntax in ${WHERE} ..."

        # Make up fixed list for GREP of include files to be
        # considered.  Search for any that are enclosed in <> rather
        # than in "".  Do this only once since the list does not
        # change.
	#
        if [ "${INCERRGREP}" = "" ] ; then
	  for FILE in `find ${RUNROOT} -name "*.h" -print` ; do
	    INCERRGREP="${INCERRGREP}|<${FILE##*/}>"
	  done
          INCERRGREP="${INCERRGREP#\|}"
        fi
	if [ "`ls -1 | egrep '\.c$|\.C$|\.h$'`" != "" ] ; then
	  egrep "'${INCERRGREP}'" *.[cCh]
	fi

      # --------------- Normal Making ---------------
      #
      else
        if [ "${VERBOSE}" = "true" ] ; then
          echo
          echo "================================================="
          echo "   Running Makefile in ${WHERE} ..."
          if [ ! "${NODEPEND}" = "true" ] ; then
            nice -20 make depend
          fi
            nice -20 make -f ${MAKEFILE} ${MAKEOPTS}

        else
          echo "Running Makefile in ${WHERE} ..."
          if [ ! "${NODEPEND}" = "true" ] ; then
            nice -20 make depend 2>&1 > /dev/null |
              egrep -vi 'makedepend:.*warning:.*(#error|#warning)'
          fi
            nice -20 make -f ${MAKEFILE} ${MAKEOPTS} > /dev/null
        fi
      fi

    rm -f ${LOCKFILE}

    fi # Ends test on locked directory

  fi # Ends test on Makefile presence

done
