#!/usr/bin/env mksh
#-
# Copyright (c) 2014
#	Thorsten Glaser <tg@mirbsd.org>
# Copyright (c) 2006
#	Thorsten Glaser <tg@freewrt.org>
#
# Derived from the MirPorts Framework "update-patches" script:
#
# Copyright (c) 2003, 2004, 2005
#	Thorsten "mirabile" Glaser <tg@MirBSD.de>
# Based upon code and idea (c) 2000
#	Marc Espie for the OpenBSD project. All rights reserved.
#
# Provided that these terms and disclaimer and all copyright notices
# are retained or reproduced in an accompanying document, permission
# is granted to deal in this work without restriction, including un-
# limited rights to use, publicly perform, distribute, sell, modify,
# merge, give away, or sublicence.
#
# This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
# the utmost extent permitted by applicable law, neither express nor
# implied; without malicious intent or gross negligence. In no event
# may a licensor, author or contributor be held liable for indirect,
# direct, other damage, loss, or other issues arising in any way out
# of dealing in the work, even if advised of the possibility of such
# damage or existence of a defect, except proven that it results out
# of said person's immediate fault when using the work as intended.

do_diff() {
	local f1=$2/$1
	local f2=$3/$1

	if [[ ! -e $f1 ]]; then
		[[ -d ${f1%/*}/. ]] || mkdir -p "${f1%/*}"
		if [[ ! -s $f2 ]]; then
			cat <<EOF
--- $f1	(non-existant)
+++ $f2	(empty)
@@ -0,0 +0,0 @@
EOF
			return 0
		fi
		touch -t 197001010000.00 "$f1"
	fi
	diff -adup "$f1" "$f2"
	return $?
}

set -A accounted
set -A edit

TRANSFORM='sed s/[.+]/\\\\&/g'
PATCHDIR=$CURDIR/patches
EXTRADIR=$CURDIR/extra

mkdir -p "$PATCHDIR"

SUBDIST=${WRKDIST##${WRKDIR1}?(/)}
if [[ -n $SUBDIST ]]; then
	mv "${WRKDIR1}.orig/${SUBDIST}" "${WRKDIR1}/${SUBDIST}.orig"
	D_BASE=${WRKDIR1}
	D_SUB=${SUBDIST}
#	D_SUBP=$D_SUB
	D_SUBP='[^/]*'
	D_CMP=$D_SUBP
else
	# WRKSRC == WRKDIR
	D_BASE=$(dirname "${WRKDIR1}")
	D_SUB=$(basename "${WRKDIR1}")
	D_SUBP=$D_SUB
	D_CMP=
fi
ORGDIST=${D_BASE}/${D_SUB}.orig

if [[ -e $WRKDIST/.patched-newfiles ]]; then
	touch "$ORGDIST/.patched-newfiles"
	patch_newfiles=1
else
	patch_newfiles=0
fi

if [[ -e $WRKDIST/../.autoreconf_done ]]; then
	touch "$ORGDIST/.autoreconf_done"
fi

DIFF_FLAGS="-adu -I \"^--- $(print -r -- "$D_SUBP.orig/" | $TRANSFORM)@@	.*\""
DIFF_FLAGS="$DIFF_FLAGS -I \"^\+\+\+ $(print -r -- "$D_SUBP/" | $TRANSFORM)@@	.*\""

(cd "${WRKDIST}"; find . -type f -print0) |&
while IFS= read -p -d '' -r file; do
	file=${file#./}
	[[ ! -e $ORGDIST/$file && $patch_newfiles = 0 ]] && continue
	for i in $DIFF_IGNOREFILES; do
		[[ $file = $i ]] && continue 2
	done
	cmp -s "$ORGDIST/$file" "$WRKDIST/$file" && continue
	print -ru2 -- "Processing ${file}..."
	# look in patchdir for an existing patchfile matching this
	cd "$PATCHDIR"
	for i in $PATCH_LIST; do
		# Ignore non-files, or old backup
		[[ ! -f $i || $i = *@(.orig|.rej|~) ]] && continue

		# Patch found. Is this the one?
		if grep "^[+-][+-][+-] $D_CMP[^/]*/$file	" "$i" >/dev/null; then
			# Multiple files in the diff?
			if [[ $(grep -c "^--- $D_CMP" "$i") -gt 1 || \
			    $(grep -c "^+++ $D_CMP" "$i") -gt 1 ]]; then
				print -ru2 -- "Cannot process, $i contains patches"
				print -ru2 -- "to multiple files! Aborting."
				print -n 'FAIL\0'
				[[ -n $SUBDIST ]] && mv \
				    "${WRKDIR1}/${SUBDIST}.orig" \
				    "${WRKDIR1}.orig/${SUBDIST}"
				exit 0
			fi
			# Multiple diffs with this file?
			let n=0
			pflst=
			for j in $PATCH_LIST; do
				[[ ! -f $j || $j = *@(.orig|.rej|~) ]] && \
				    continue
				grep "^[+-][+-][+-] $D_CMP[^/]*/$file	" \
				    "$j" >/dev/null || continue
				let n++
				pflst="$pflst '$j'"
			done
			if (( n != 1 )); then
				print -ru2 -- "Cannot process, file $file"
				print -ru2 -- "is contained in multiple patches:"
				print -ru2 -- "$pflst"
				print -n 'FAIL\0'
				[[ -n $SUBDIST ]] && mv \
				    "${WRKDIR1}/${SUBDIST}.orig" \
				    "${WRKDIR1}.orig/${SUBDIST}"
				exit 0
			fi
			# No, process this patch

			accounted+=("$i")
			# found it, copy preamble before comparision
			( sed -e "/^--- /,\$d" <"$i"; \
			  cd "$D_BASE" && do_diff "$file" "$D_SUB.orig" "$D_SUB" \
			) >"$i.new"
			# did it change? mark it as changed
			tfile=$(print -r -- "$file" | $TRANSFORM)
			if eval diff "$(print -r -- "${DIFF_FLAGS}" | sed \
			    "s#@@#${tfile}#g")" '"$i" "$i.new"' 1>&2; then
				rm "$i.new"
			else
				print -ru2 -- "Patch $i for $file updated"
				mv "$i" "$i.orig"
				mv "$i.new" "$i"
				edit+=("$i")
			fi
			continue 2
		fi
	done

	# Build a sensible name for the new patch file
	patchname=patch-${file//[\/.- ]/_}
	print -ru2 -- "No patch-* found for $file, creating $patchname"
	( cd "$D_BASE" && do_diff "$file" "$D_SUB.orig" "$D_SUB" ) >"$patchname"
	edit+=("$patchname")
	accounted+=("$patchname")
done

# Verify all patches accounted for
cd "$PATCHDIR"
for i in *; do
	[[ ! -f $i || $i = *@(.orig|.rej|~) ]] && continue
	grep '^\\ No newline at end of file' "$i" >/dev/null && \
	    print -ru2 -- "*** Patch $i needs manual intervention"
	found=0
	for j in "${accounted[@]}"; do
		[[ $i = "$j" ]] || continue
		found=1
		break
	done
	(( found )) || print -ru2 -- "*** Patch $i not accounted for"
done

for i in "${edit[@]}"; do
	print -nr -- "$i"
	print -n '\0'
done
[[ -n $SUBDIST ]] && mv "${WRKDIR1}/${SUBDIST}.orig" "${WRKDIR1}.orig/${SUBDIST}"
exit 0
