#! /bin/sh

# Script to tell whether a patch has been applied to a tree or not.
# Assume patch is in diff -u form, and applies in dir with -p1.

usage()
{
    [ $# -eq 0 ] || echo "$@" >&2
    echo Usage "isapplied <directory> <patch>" >&2
    exit 1
}

[ $# -eq 2 ] || usage
[ -d $1 ] || usage "$1 is not a directory"
[ -f $2 ] || usage "$2 is not a file"

# Convert $2 to absolute.
case "$2"
in
    /*) PATCH="$2" ;;
    *) PATCH="`pwd`/$2" ;;
esac

# Grab unpredictable dirname.
DIRNAME=${TMPDIR:-/tmp}/`od -N64 -x -w4000 < /dev/urandom | tr -d ' \n'`

trap "rm -rf $DIRNAME" EXIT

mkdir $DIRNAME || exit 1

case "$PATCH" in
    *.bz2) CAT=bzcat;;
    *.gz) CAT=zcat;;
    *) CAT=cat;;
esac

copy_tree()
{
    # Copy only files which are mentioned in patch.
    # eg. +++ working-2.4.0-test11-5/net/ipv4/netfilter/ipt_MASQUERADE.c	Fri Dec  1 17:56:02 2000
    for f in `$CAT $PATCH | grep '^+++ ' | cut -d/ -f2- | cut -d'	' -f1`
    do
	[ -d `dirname $2/$f` ] || mkdir -p `dirname $2/$f`
	[ -f $1/$f ] && cp $1/$f $2/$f
    done
}

check_reversed()
{
    copy_tree "$1" $DIRNAME/tmp
    if pushd $DIRNAME/tmp >/dev/null; then :
    else
	echo Can\'t change into $DIRNAME/tmp >&2
	exit 1
    fi
    MISSING_FILES=`$CAT $PATCH | patch -R -s -f -p1 | grep -c "No file to patch"`

    REJECTS="`find . -name '*.rej' -exec cat {} \; | grep -c '^\*\*\* '`"
    popd >/dev/null
    rm -rf $DIRNAME/tmp
}

HUNKS="`$CAT $PATCH | grep -c ^@@`"
if [ $HUNKS = 0 ]; then
    echo No hunks found in patch\! >&2
    exit 1
fi

check_reversed "$1"

# Any missing files means not applied...
if [ "$MISSING_FILES" -ne 0 ]
then
    echo `basename $PATCH` NOT APPLIED \($MISSING_FILES missing files\)
    exit 1
fi

# 2/3 rejects or more?  Not applied...
if [ `expr $REJECTS \* 3 / 2` -ge $HUNKS ]
then
    echo `basename $PATCH` NOT APPLIED \($REJECTS rejects out of $HUNKS hunks\)
    exit 1
fi

echo `basename $PATCH` ALREADY APPLIED \($REJECTS rejects out of $HUNKS hunks\).
exit 0
