#!/bin/bash
#####################################################################
#                   mdiff                                           #
# This shell script compares two MCTDH_directories and lists the    #
# files which appear in only one of the two MCTDH directories, but  #
# not in the other one. mdiff may also show the differences between #
# the files using diff | ediff or mgdiff or kdiff3.                 #
# HDM 12/03                                                         #
#####################################################################

#-----------------------------------------------------------------------
# FUNCTION searchf. Find files which exist in only one of the dirs.
#-----------------------------------------------------------------------
searchf() {
   for i in $fl1 ; do
      unset found
      for j in $fl2 ; do
         if [ "$i" = "$j" ] ; then
            found=1
            break
         fi
      done
      if [ -z "$found" ] ; then
         echo $i
         foundlist="$foundlist $i"
         num=$(($num+1))
      else
          fl2=`echo $fl2 | cut -d' ' -f2-`
          if [ -n "$cmp" ] ; then
             if cmp $dir1/$i $dir2/$i -s ; then
                numi=$(($numi+1))
             else
                difflist=${difflist}`echo -e "\n$i" `
                numd=$(($numd+1))
             fi
          fi
      fi
   done
}

# FUUNCTION searchw. Find files which differ only by whitespace.
searchw() {
   for i in $difflist ; do
      equal=0
      diff -q -w $dir1/$i $dir2/$i > /dev/null && equal=1
      if [ $equal = 1 ]; then
         spacelist=${spacelist}`echo -e "\n$i"`
         numsp=$(($numsp+1))
      else
         diff2list=${diff2list}`echo -e "\n$i"`
         numd2=$(($numd2+1))
      fi
   done
}
#-----------------------------------------------------------------------
#  End of functions searchf and searchw
#-----------------------------------------------------------------------

EDIFF='cat'
type ediff &>  /dev/null && EDIFF='ediff'
minus40='----------------------------------------'
 star40='****************************************'
echo "$minus40$minus40"
oldpwd=`pwd`

# --- Find the argument dir (last argument).
it=1
for i in "$@" ; do
   i1=$i
   if [ -z "${it#-[eirR]}" ]; then unset i1   # all options with arguments
   elif [ -z "${i##-*}" ];    then unset i1 ; fi
   it=$i
done
dir=${i1:-$MCTDH_DIR}

# --- Set file names and determine the total number of backups.

if [ -z "$dir" ]; then dir=$MCTDH_DIR ; fi
if [ -z "$dir" ]; then
   echo " MCTDH_DIR is empty!"
   exit
elif [ -d "$dir" ]; then
   cd $dir
   dir=`pwd`
   mdir=`basename $dir`
   bdir=$MCTDH_BACKUP/$mdir
   last=${bdir}_last
   log=${bdir}_log
else
   echo " ### WARNING: The directory $dir does not exist!"
fi
nrtot=0
if [ -f "$last" ]; then
   nrtot=`wc -l $last `
   nrtot=`echo $nrtot | cut -d' ' -f1 `
fi

# --- This is to check that -d, -D, -r -R have arguments (e.g. -R1).
echo " $@" | grep -i ' -r'  > /dev/null && restore=1

#-----------------------------------------------------------------------
#  Definitions :
#-----------------------------------------------------------------------

purp1="Purpose : Comparison of content of two MCTDH-directories. List the"
purp2="files which appear on only one of the two MCTDH-directories."
purp3="Excluded are binary and object files and files like *.dvi, *~ etc."
usage="Usage   : mdiff [ -a -c -d -m -e -i -p -r -R -h ] dir1 [dir2]."
help1='-h     : print this help text.'
help2='-a     : Compare all files except object/, bin/.+/ and obsolete/ ones.'
help3='-c     : Compare files and list those which differ.'
help4='-d     : Show differences (diff) between files that differ.'
hlp4a='-m     : Show differences (mgdiff) between files that differ.'
hlp4b='-k     : Show differences (kdiff3) between files that differ.'
help5='-e pat : Exclude file the names of which match pattern pat. '
help6='-i pat : Include only file the names of which match pattern pat. '
help7='-p     : print file list (and do nothing else).'
hlp2a='-r nun : Compare $MCTDH_DIR (or dir1) with backup number num.'
hlp2b='-R num : Compare $MCTDH_DIR (or dir1) with backup, counting from the end.'
hlp2c='-t     : Touch files of dir2 which differ.'
hlp2d='         Sets -c and, if no dir or -r|R option given, -R1.'
hlp2e='-W     : Ignore all white spaces when deciding if file differ.'
help8='The comparison is between dir1 and dir2.'
help9='If dir2 is not given, $MCTDH_DIR is assumed.'

#-----------------------------------------------------------------------
#  Read the options (if any).
#-----------------------------------------------------------------------

while getopts ":hWacdmkte:i:R:r:p" opt; do
    case $opt in
    h  ) help=1 ;;
    a  ) all=1  ;;
    c  ) cmp=1  ;;
    d  ) cmp=1; diff=1 ;;
    m  ) cmp=1; diff=1; mg=1 ;;
    k  ) cmp=1; diff=1; kd=1 ;;
    e  ) if [ -z "$excl" ]; then
            excl=$OPTARG
         else
            excl="$excl|$OPTARG"
            exclm=1
         fi ;;
    i  ) if [ -z "$incl" ]; then
            incl=$OPTARG
         else
            incl="$incl|$OPTARG"
            inclm=1
         fi ;;
    p  ) pr=1   ;;
    t  ) touch=1; cmp=1 ;;
    r  ) rst=1
         unset ok
         echo $OPTARG | egrep '^[0-9]*$' &> /dev/null && ok=1
         if [ -z "$OPTARG" ] || [ -z "$ok" ] ; then
            echo " A positive integer must follow -r, not: $OPTARG "
            exit
         fi
         if [ -n "$nrst2" ] ; then
            echo " No more than two -r or -R option allowed."
            exit
         else
            nrst2=$nrst
            nrst=$OPTARG
         fi ;;
    R  ) rst=1
         unset ok
         echo $OPTARG | egrep '^[0-9]*$' &> /dev/null && ok=1
         if [ -z "$OPTARG" ] || [ -z "$ok" ] ; then
            echo " A positive integer must follow -R, not: $OPTARG "
            exit
         fi
         if [ -n "$nrst2" ] ; then
            echo " No more than two -r or -R options allowed."
            exit
         else
            nrst2=$nrst
            nrst=$(($nrtot+1-$OPTARG))
         fi ;;
    W  ) wspc=1; cmp=1  ;;
    \? ) echo ' Unkown option!'
         echo $usage
         echo ' -h provides a help text.'
         exit 1 ;;
  esac
done
shift $(($OPTIND - 1))

if [ -n "$exclm" ]; then excl="($excl)" ; fi
if [ -n "$inclm" ]; then incl="($incl)" ; fi

# --- Set default values for touch if no dir is given.
if [ -n "$touch" ] && [ -z "$1" ] && [ -z "$rst" ] ; then
   rst=1; nrst=$nrtot
fi

cd $oldpwd
if [ -z "$dir1" ] ; then dir1=$1 ; fi
dir2="${2:-$MCTDH_DIR}"

if [ -n "$rst" ]; then
   if [ -n "$2" ]; then
      echo " No second directory must be given when option -r or -R is set."
      exit
   elif [ $nrst -lt 1 ] || [ $nrst -gt $nrtot ]; then
      echo " There is no such backup (-r -R option)"
      echo " Total number of backup files: $nrtot ,  (1-$nrtot)."
      echo " You requested file No. $nrst"
      echo " Log file is: $log"
      echo " I show the tail of it:"
      echo " "
      tail -n 25 $log
      echo " "
      exit
   fi
   dir1=$MCTDH_BACKUP/`cat $last | tr '\n' ' ' | cut -d' ' -f$nrst `
   dir2=$dir
   if [ -n "$nrst2" ]; then
      if [ $nrst2 -lt 1 ] || [ $nrst2 -gt $nrtot ]; then
         echo " There is no such backup (-r -R option)"
         echo " Total number of backup files: $nrtot ."
         echo " You requested file No. $nrst2 for second backup file."
         echo " Log file is: $log"
         echo " I show the tail of it:"
         echo " "
         tail -n 25 $log
         echo " "
         exit
      fi
      dir2=$MCTDH_BACKUP/`cat $last | tr '\n' ' ' | cut -d' ' -f$nrst2 `
   fi
fi

if [ -z "$pr" ] && [ -z "$help" ] && [ -z "$dir1" ]; then
   echo " ######   No directory given! ###### "
   help=1
elif [ -n "$pr" ] && [ -z "$dir1" ]; then
   dir1=$dir2
fi
if [ -n "$help" ]; then
    echo "$purp1"
    echo "          $purp2"
    echo "          $purp3"
    echo "$usage"
    echo " $help1"
    echo " $help2"
    echo " $help3"
    echo " $help4"
    echo " $hlp4a"
    echo " $hlp4b"
    echo " $help5"
    echo " $help6"
    echo " $help7"
    echo " $hlp2a"
    echo " $hlp2b"
    echo " $hlp2c"
    echo " $hlp2d"
    echo " $hlp2e"
    echo ' '
    echo "    $help8"
    echo "    $help9"
    echo "    dir1 = $dir1"
    echo "    dir2 = $dir2"
    echo ' '
    echo 'Examples: '
    echo " mdiff -d -i '/source/propwf/' ../mctdh84.2 | less"
    echo " Show the differences (using diff) between ../mctdh84.2"\
         "and the current version."
    echo " The task is restricted to files of source/propwf."
    echo " NB: egrep is used for -i and egrep -v is used for -e."
    echo ' '
    echo " mdiff -R1 -c"
    echo " List files which differ in the current version from last backup."
    echo ' '
    echo " mdiff -R1 -R2 -m -i source -e analyse -e potfit"
    echo " Show the differences (using mgdiff) between last"\
         "and before last backup."
    echo " Compare only sorce files except those from potfit and analyse."
    echo ' '
    echo " mdiff -t -i /source/"
    echo " Touch source files which differ in the current version"\
         "from last backup."
    echo ' '
    echo " mdiff mctdh84.2 mctdh84.3"
    echo " List files which exist in only one of the two MCTDH directories."
    echo "$minus40$minus40"
    if [ -z "$pr" ] && [ -z "$help" ] && [ -z "$dir1" ]; then
        echo " ######   No directory given! ###### "
    echo "$minus40$minus40"
    fi
    exit
fi

if [ -n "${dir2%%/*}" ] ; then
   if [ -d $dir2 ]; then cd $dir2; dir2=`pwd`; cd $oldpwd; fi
fi
if [ -d $dir1 ] ; then cd $dir1; dir1=`pwd`; cd $oldpwd; fi
num=0
numd=0
numi=0
numd2=0
numsp=0

echo ' Working    Directory: '$dir1
echo ' Comparison Directory: '$dir2
echo ' '
if [ ! -d "$dir1" ] ; then
   echo "There is no directory $dir1"
   echo "on:  $oldpwd"
   exit
fi
if [ ! -d "$dir2" ] ; then
   echo "There is no directory $dir2"
   echo "on:  $oldpwd"
   exit
fi


#-----------------------------------------------------------------------
#  Exclude list.
#-----------------------------------------------------------------------
EXCLUDE='(\.nfs|/obsolete/|/\.svn/|mctdhall|.*_bk[0-9].*|.*_md[0-9].*|\./bin/binary/|\./object/|.*\.pyc|.*\.pdf|.*\.ps|.*\.dvi|.*\.aux|/install/Makefile_.*|\./doc/.*\.log|\./doc/guide/guide\.i.*|\./doc/guide/guide\.l.*|\./doc/guide/guide\.b.*|\./doc/guide/guide\.toc|.*\.swp$|.*~$|\./source/SUBR|\./source/SFILES|\./install/save-.*|\./install/dependencies|\./install/.*\.cnf$|\./install/platform\.cnf\.csh$|#.*#|MCTDH_client|MCTDH_IFORT_.*|include/.*\.inc\.old|include/.*\.inc\.new|include/.*\.inc\.orig|\./source/.*\.F\.new|\./source/.*\.F\.old|\./source/.*\.F\.orig|\./source/.*\.F\.save|Makefile\.new|Makefile\.save|Makefile\.original)'

EXEX='(/obsolete/|/\.svn/|\.pyc|\./bin/binary/|\./object/|.*\.swp$|.*~$|#.*#)'

#-----------------------------------------------------------------------
#  Generate the flists.
#-----------------------------------------------------------------------

cd $dir1
if [ -z "$all" ]; then
   set -f
   flist1=`find . -type f -print | egrep -v "$EXCLUDE" `
   set +f

   fl1=`find ./doc/guide/figures -type f -print ; \
           find ./doc/guide -name 'guide.bbl' -print ; \
           find ./doc/examples -type f -print ; \
           find ./bin/python -type f -print  `
   fl1=`echo "$fl1" |egrep -v \
        '(/\.svn/|\.pyc|mctdhform\.ps|/obsolete/|.*\.swp$|.*~$|#.*#)'`
else
   set -f
   flist1=`find . -type f -print | egrep -v "$EXEX" `
   fl1=`find ./bin/python -type f -print| egrep -v '(/obsolete/|/\.svn/|\.pyc)' `
   set +f
fi

flist1=`echo "$flist1"; echo "$fl1" `
flist1=`echo "$flist1" | sort -u `

if [ -n "$excl" ]; then
   flist1=`echo "$flist1" | egrep -v "$excl" `
fi

if [ -n "$incl" ]; then
   flist1=`echo "$flist1" | egrep  "$incl" `
fi



cd $dir2
if [ -z "$all" ]; then
   set -f
   flist2=`find . -type f -print | egrep -v "$EXCLUDE" `
   set +f

   fl2=`find ./doc/guide/figures -type f -print ; \
           find ./doc/guide -name 'guide.bbl' -print ; \
           find ./doc/examples -type f -print ; \
           find ./bin/python -type f -print  `
   fl2=`echo "$fl2" |egrep -v \
        '(/\.svn/|\.pyc|mctdhform\.ps|/obsolete/|.*\.swp$|.*~$|#.*#)'`
   flist2=`echo "$flist2"; echo "$fl2" `
   flist2=`echo "$flist2" | sort -u `

else
   set -f
   flist2=`find . -type f -print | egrep -v "$EXEX" | sort `
   set +f
fi

if [ -n "$excl" ]; then
   flist2=`echo "$flist2" | egrep -v "$excl" `
fi

if [ -n "$incl" ]; then
   flist2=`echo "$flist2" | egrep  "$incl" `
fi



n1=`echo "$flist1" | wc -l `
n2=`echo "$flist2" | wc -l `
if [ -z "$flist1" ] ; then n1=0 ; fi
if [ -z "$flist2" ] ; then n2=0 ; fi
if [ -n "$pr" ]; then
   if [ "$dir1" != "$dir2" ]; then
   echo "There are $n1 files on $dir1"
   echo "$flist1"
   echo "There are $n1 files on $dir1"
   echo "$minus40$minus40"
   fi
   echo "There are $n2 files on $dir2"
   echo "$flist2"
   echo "There are $n2 files on $dir2"
   echo "$minus40$minus40"
   exit
fi

if [ "$dir1" != "$dir2" ]; then
   echo "There are $n1 files on $dir1"
fi
echo "There are $n2 files on $dir2"

#-----------------------------------------------------------------------
#  Perform the comparison.
#-----------------------------------------------------------------------

unset foundlist
length=`echo $dir1 | wc -c`
echo ' '
if [ $length -gt 42 ] ; then
   echo "The following files do not exist on"
   echo " ---  $dir1  ---"
else
   echo "The following files do not exist on $dir1"
fi

fl2=`echo "$flist1"  | egrep -v '(\./doc/.*|\./source/.*)' `
fl1=`echo "$flist2"  | egrep -v '(\./doc/.*|\./source/.*)' `
searchf

fl2=`echo "$flist1"  | fgrep  './doc/' `
fl1=`echo "$flist2"  | fgrep  './doc/' `
searchf

fl2=`echo "$flist1"  | fgrep  './source/' `
fl1=`echo "$flist2"  | fgrep  './source/' `
searchf

if [ -z "$foundlist" ] ; then echo '------ none ------' ; fi

if [ -n "$touch" ] && [ -n "$foundlist" ]; then
 touch $foundlist
 echo "These files touched on $dir2"
fi
cmp1=$cmp
unset cmp
num1=$num
num=0
unset foundlist
length=`echo $dir2 | wc -c`
echo ' '
if [ $length -gt 42 ] ; then
   echo "The following files do not exist on"
   echo " ---  $dir2  ---"
else
   echo "The following files do not exist on $dir2"
fi

fl1=`echo "$flist1"  | egrep -v '(\./doc/.*|\./source/.*)' `
fl2=`echo "$flist2"  | egrep -v '(\./doc/.*|\./source/.*)' `
searchf

fl1=`echo "$flist1"  | fgrep  './doc/' `
fl2=`echo "$flist2"  | fgrep  './doc/' `
searchf

fl1=`echo "$flist1"  | fgrep  './source/' `
fl2=`echo "$flist2"  | fgrep  './source/' `
searchf

if [ -z "$foundlist" ] ; then echo '------ none ------' ; fi

if [ -n "$cmp1" ] ; then
   if [ -n "$wspc" ]; then searchw ; fi
   if [ $numsp -gt 0 ]; then
      difflist=$diff2list
      numd=$numd2
      echo ' '
      echo -n "The following files differ only in white space"
      echo "$spacelist"
   fi
   echo ' '
   echo -n "The following files exist on both dirs, but differ"
   if [ -z "$difflist" ] ; then
      echo ' '
      echo '------ none ------'
   else
      echo "$difflist"
   fi
   if [ -n "$touch" ] && [ -n "$difflist" ]; then
      touch $difflist
      echo "These files touched on $dir2"
   fi
fi

if [ -n "$diff" ] && [ $numd -gt 0 ]; then
   echo "$minus40$minus40"
   echo " <  $dir1"
   echo " >  $dir2"
   echo "$minus40$minus40"
   for i in $difflist ; do
      if [ -z "$mg" ] && [ -z "$kd" ]; then
      echo "####  $i"
         diff -d  ${dir1}${i#*.} ${dir2}${i#*.} | $EDIFF
      echo "####  $i"
      echo "$minus40$minus40"
      elif [ -n "$mg" ]; then
         mgdiff -args -d  -geometry 1250X900+0+0 \
               ${dir1}${i#*.} ${dir2}${i#*.}
      elif [ -n "$kd" ]; then
         kdiff3  -geometry 1250X900+0+0 \
               ${dir1}${i#*.} ${dir2}${i#*.}
      fi
   done
fi


echo " "
echo "$num1 files do not exist on $dir1 "
echo "$num files do not exist on $dir2 "
if [ -n "$cmp1" ] ; then echo "$numi files are identical " ; fi
if [ -n "$wspc" ] ; then echo "$numsp files differ only by whitespace " ; fi
if [ -n "$cmp1" ] ; then echo "$numd files differ " ; fi
if [ -n "$touch" ] ; then
   num2=$(($numd+$num1))
   echo "$num2 files touched "
fi
echo "$star40$star40"
exit

