#! /bin/bash
# patchview, Copyright (C) 2005 Randy Dunlap <rdunlap@xenotime.net>
# modified to support multiple patchfiles by Chris Cleeland <cleeland@ociweb.com>
# modified to compare patch results of 2 patchfiles by Jan Blunck <jblunck@suse.de>
# License:  GPL v2.
#
# uses patchutils (lsdiff) and tkdiff

PROG=${0##*/}
VERSION=008

# usage: help message and exit
function usage()
{
	echo "usage: $PROG [-f] [-s] [-t] srctree patchfile(s) {ver. $VERSION}"
	echo "       $PROG -d srctree patchfile1 patchfile2"
	echo "  -f : force tkdiff even if 'patch' has errors"
	echo "  -s : single tkdiff even if patchfile contains multiple files"
	echo "  -t : use tkdiff even if mtkdiff is available"
	echo "  -d : compare two patchfiles"
	exit 1
}

# cleanup: clean up temporary files
function cleanup()
{
	# close any remaining viewers
	kill `jobs -p` &> /dev/null

	rm -rf $WORKDIR
}

# strip_filename:
# input: filename being patched
# returns 'base', which is directory level(s) (path) without filename
function strip_filename()
{
	fn=$1
	len=${#fn}
	fx=$((len - 1))
	base=""
	while [ 1 -eq 1 ]; do
		if [ ${fn:$fx:1} == "/" ]; then
			##fx=$((fx - 1))
			base=${fn:0:$fx}
			break
		fi
		fx=$((fx - 1))
		if [ $fx -eq 0 ]; then
			break
		fi
	done
}

# call cleanup function when script finishes or gets killed
trap cleanup EXIT

diff=0
force=0
single=0
tkonly=0
mtkdiff=0
VIEWER=${DIFFVIEWER-"tkdiff"}
if [ -x "`which mtkdiff`" ]; then
	VIEWER="mtkdiff"
	mtkdiff=1
fi
# or maybe "sh -c colordiff" would work

while [ -n "$1" ]
do
	case $1 in
	-d)
		diff=1
		;;
	-f)
		force=1
		;;
	-s)
		single=1
		tkonly=1
		mtkdiff=0
		VIEWER="tkdiff"
		;;
	-t)
		tkonly=1
		mtkdiff=0
		VIEWER="tkdiff"
		;;
    	-*)
		if [ "${1#-}" = '?' ]; then
			usage
		fi
		;;
    	*)
		# Accept filename or report a warning
		if [ -z "${srctree}" ]; then
			srctree=$1; shift
			declare -a patchfiles
			patchfiles=($@)
			break
		else
			usage
		fi
		;;
    	esac

    	# Shift argument 2 into argument 1's slot.  Loop to check the argument.
    	shift
done

if [ "${patchfiles[*]}" = "" -o "$srctree" = "" ]; then
	usage
fi

if [ $diff -ne 0 -a ${#patchfiles[@]} -ne 2 ] ; then
	usage
fi

echo "Using $VIEWER"

# setup temp working directory
if [ -d ~/tmp ]; then
	TMPDIR=~/tmp
else
	TMPDIR=/tmp
fi
if [ ! -d ${TMPDIR} ]; then
	mkdir ${TMPDIR} || echo "failed mktemp for patch files dir."
fi

WORKDIR=`mktemp -d -p ${TMPDIR} src.XXXXXX` || \
	{ echo "failed mktemp for patch files dir."; exit 1; }

pfiles=`lsdiff --strip 1 -h ${patchfiles[*]} | sort | uniq`

for pf in $pfiles ; do
	strip_filename $pf	# sets 'base'
	if [ "$base" != "" ]; then
		if [ ! -e $WORKDIR/$base ]; then
			if [ $diff -ne 0 ] ; then
				mkdir -p $WORKDIR/${patchfiles[0]}/$base
				mkdir -p $WORKDIR/${patchfiles[1]}/$base
			else
				mkdir -p $WORKDIR/$base
			fi
		fi
	fi
	if [ -e $srctree/$pf ]; then
		if [ $diff -ne 0 ] ; then
			cp -a $srctree/$pf $WORKDIR/${patchfiles[0]}/$pf
			cp -a $srctree/$pf $WORKDIR/${patchfiles[1]}/$pf
		else
			cp -a $srctree/$pf $WORKDIR/$pf
		fi
	else
		# work around the .orig file permissions of 000
		if [ $diff -ne 0 ] ; then
			touch $WORKDIR/${patchfiles[0]}/$pf
			touch $WORKDIR/${patchfiles[1]}/$pf
		else
			touch $WORKDIR/$pf
		fi
		##echo "##### creating empty $WORKDIR/$pf #####"
	fi
done

if [ $diff -ne 0 ] ; then
    patch -p1 -bs -d $WORKDIR/${patchfiles[0]} < ${patchfiles[0]}
    if [ $? -ne 0 ] && [ $force -eq 0 ]; then
	echo "patch errors, use '$PROG -f' to force continuation"
	exit 1
    fi
    patch -p1 -bs -d $WORKDIR/${patchfiles[1]} < ${patchfiles[1]}
    if [ $? -ne 0 ] && [ $force -eq 0 ]; then
	echo "patch errors, use '$PROG -f' to force continuation"
	exit 1
    fi
else
    for patchfile in ${patchfiles[@]}
      do
      patch -p1 -bs -d $WORKDIR < $patchfile
      sts=$?
      if [ $sts -ne 0 ] && [ $force -eq 0 ]; then
	  echo "patch errors, use '$PROG -f' to force continuation"
	  exit 1
      fi
    done
fi

case $VIEWER in
mtkdiff)
	i=0
	argv[i++]="-gdesc"
	argv[i++]=`diffstat ${patchfiles[0]}`
	for pf in $pfiles ; do
		argv[i++]="-fname"
		argv[i++]="$pf"
		if [ $diff -ne 0 ] ; then
			argv[i++]="$WORKDIR/${patchfiles[0]}/$pf"
			argv[i++]="$WORKDIR/${patchfiles[1]}/$pf"
		else
			argv[i++]="$WORKDIR/$pf.orig"
			argv[i++]="$WORKDIR/$pf"
		fi
	done
	mtkdiff "${argv[@]}"
	;;

*)
	for pf in $pfiles ; do
		if [ $diff -ne 0 ]; then
			$VIEWER "$WORKDIR/${patchfiles[0]}/$pf" "$WORKDIR/${patchfiles[1]}/$pf" &
		else
			$VIEWER $WORKDIR/$pf.orig $WORKDIR/$pf &
		fi
		if [ ${single} -eq 1 ]; then
			wait # for viewer to exit
		fi
	done

	if [ ${single} -eq 0 ]; then
		wait # for all viewers to exit
	fi
	;;

esac
