#!/bin/sh
#
# Script to automatically install all Wine Staging patches
#
# Copyright (C) 2015 Sebastian Lackner
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#

# Show usage information
usage()
{{
	echo ""
	echo "Usage: ./patchinstall.sh [DESTDIR=path] [--all] [-W patchset] [patchset ...]"
	echo ""
	echo "Autogenerated script to apply all Wine Staging patches on your Wine"
	echo "source tree. This script replaces and enhances the old method of"
	echo "using a Makefile."
	echo ""
	echo "Configuration:"
	echo "  DESTDIR=path         Specify the path to the wine source tree"
	echo "  --all                Select all patches"
	echo "  --help               Display this help and exit"
	echo "  --no-patchlist       Do not apply patchlist (needed for 'wine --patches')"
	echo "  --no-autoconf        Do not run autoreconf and tools/make_requests"
	echo "  -W patchset          Exclude a specific patchset"
	echo ""
	echo "Backends:"
	echo "  --backend=patch      Use regular 'patch' utility to apply patches (default)"
	echo "  --backend=epatch     Use 'epatch' to apply patches (Gentoo only)"
	echo "  --backend=git-am     Use 'git am' to apply patches"
	echo "  --backend=git-apply  Use 'git apply' to apply patches"
	echo "  --backend=stg        Import the patches using stacked git"
	echo ""
}}

# Critical error, abort
abort()
{{
	echo "ERROR: $1" >&2
	exit 1
}}

{patch_helpers}

# Default settings
patch_enable_all 0
enable_patchlist=1
enable_autoconf=1
patchlist="/dev/null"
backend="patch"
enable=1

if test "$#" -eq 0; then
	abort "No commandline arguments given, don't know what to do."
fi

while test "$#" -gt 0; do
	if patch_enable "$1" "$enable"; then
		shift
		enable=1
		continue
	fi

	if test "$enable" -ne 1; then
		abort "Wrong use of -W commandline argument, expected patchname."
	fi

	case "$1" in
		DESTDIR=*)
			DESTDIR="${{1#*=}}"
			shift
			;;

		--all)
			patch_enable_all 1
			shift
			;;

		--backend=*)
			backend="${{1#*=}}"
			shift
			;;

		--help)
			usage
			exit 0
			;;

		--no-patchlist)
			enable_patchlist=0
			shift
			;;

		--no-autoconf)
			enable_autoconf=0
			shift
			;;

		-W)
			enable=2
			shift
			;;

		*)
			abort "Unknown commandline argument $1"
			exit 1
	esac
done

if test "$enable" -ne 1; then
	abort "Missing argument for -W, expected patchname."
fi

# Apply the patches using gitapply.sh, a small wrapper around 'patch'
if test "$backend" = "patch"; then

	patch_apply ()
	{{
		echo "Applying $1"
		if ! ../debian/tools/gitapply.sh -d "$DESTDIR" < "$1"; then
			abort "Failed to apply patch, aborting!"
		fi
	}}

# 'epatch' backend - used on Gentoo
elif test "$backend" = "epatch"; then

	patch_apply ()
	{{
		if grep -q "^GIT binary patch" "$1"; then
			if ! ../debian/tools/gitapply.sh -d "$DESTDIR" < "$1"; then
				abort "Failed to apply patch, aborting!"
			fi
		else
			local patch="$(readlink -f "$1")"
			if ! (cd "$DESTDIR" && epatch "$patch"); then
				abort "Failed to apply patch, aborting!"
			fi
		fi
	}}

# GIT backend - apply patches using 'git am'
elif test "$backend" = "git" -o "$backend" = "git-am"; then

	patch_apply ()
	{{
		echo "Applying $1"
		if ! cat "$1" | (cd "$DESTDIR" && git am); then
			abort "Failed to apply patch, aborting!"
		fi
	}}

# Git apply backend
elif test "$backend" = "git-apply"; then

	patch_apply ()
	{{
		echo "Applying $1"
		if ! cat "$1" | (cd "$DESTDIR" && git apply); then
			abort "Failed to apply patch, aborting!"
		fi
	}}

# Stacked GIT backend - import the patches (mainly for developers)
elif test "$backend" = "stg"; then

	# Only import the regular patches, no autogenerated ones -
	# moreover, don't run autoreconf or ./tools/make_requests.
	enable_patchlist=0
	enable_autoconf=0

	patch_apply ()
	{{
		echo "Applying $1"
		if ! echo "staging/$1" | cat - "$1" | (cd "$DESTDIR" && stg import); then
			abort "Failed to apply patch, aborting!"
		fi
	}}

else
	abort "Selected backend $backend not supported."
fi


{patch_resolver}


if test -z "$DESTDIR" -a -f ./tools/make_requests; then
	DESTDIR="$(pwd)"

elif test ! -f "$DESTDIR/tools/make_requests"; then
	abort "DESTDIR does not point to the Wine source tree."
fi

# To make sure we find all the patches and tools switch to the patches directory now
script="$(readlink -f "$0")"
curdir="$(dirname "$script")"
if test -f "$curdir/patchinstall.sh"; then
	if ! cd "$curdir"; then
		abort "Failed to change working directory to $curdir."
	fi
elif test ! -f ./patchinstall.sh; then
	abort "Failed to find patch directory."
fi

# If autoupdate is enabled then create a tempfile to keep track of all patches
if test "$enable_patchlist" -eq 1; then
	patchlist=$(mktemp)
	if test ! -f "$patchlist"; then
		abort "Unable to create temporary file for patchlist."
	fi
fi


{patch_apply}


if test "$enable_patchlist" -eq 1; then

	# Generate a temporary patch containing the patchlist and apply it
	patch_data=$(cat "$patchlist" | sort)
	patch_lines=$(echo "$patch_data" | wc -l)
	if test ! -z "$patch_data"; then
		patch_lines=$((${{patch_lines}}+23))
		cat > "$patchlist" <<EOF
From: Wine Staging Team <webmaster@fds-team.de>
Subject: Autogenerated patch list.

diff --git a/include/wine/library.h b/include/wine/library.h
--- a/include/wine/library.h
+++ b/include/wine/library.h
@@ -43,6 +43,7 @@ extern const char *wine_get_data_dir(void);
 extern const char *wine_get_server_dir(void);
 extern const char *wine_get_user_name(void);
 extern const char *wine_get_version(void);
+extern const void *wine_get_patches(void);
 extern const char *wine_get_build_id(void);
 extern void wine_init_argv0_path( const char *argv0 );
 extern void wine_exec_wine_binary( const char *name, char **argv, const char *env_var );
diff --git a/libs/wine/config.c b/libs/wine/config.c
index a273502..0a3182f 100644
--- a/libs/wine/config.c
+++ b/libs/wine/config.c
@@ -478,6 +478,${{patch_lines}} @@ const char *wine_get_version(void)
     return PACKAGE_VERSION;
 }}
 
+static const struct
+{{
+    const char *author;
+    const char *subject;
+    int revision;
+}}
+wine_patch_data[] =
+{{
${{patch_data}}
+    {{ NULL, NULL, 0 }}
+}};
+
+/* return the applied non-standard patches */
+const void *wine_get_patches(void)
+{{
+    return &wine_patch_data[0];
+}}
+
 /* return the build id string */
 const char *wine_get_build_id(void)
 {{
diff --git a/libs/wine/wine.def b/libs/wine/wine.def
index ed315bd..5b42029 100644
--- a/libs/wine/wine.def
+++ b/libs/wine/wine.def
@@ -83,6 +83,7 @@ EXPORTS
     wine_get_sortkey
     wine_get_user_name
     wine_get_version
+    wine_get_patches
     wine_init
     wine_init_argv0_path
     wine_is_dbcs_leadbyte
diff --git a/libs/wine/wine.map b/libs/wine/wine.map
index 2159fac..7cb2918 100644
--- a/libs/wine/wine.map
+++ b/libs/wine/wine.map
@@ -90,6 +90,7 @@ WINE_1.0
     wine_get_ss;
     wine_get_user_name;
     wine_get_version;
+    wine_get_patches;
     wine_init;
     wine_init_argv0_path;
     wine_is_dbcs_leadbyte;
EOF
		patch_apply "$patchlist"
	fi
	rm "$patchlist"
fi

if test "$enable_autoconf" -eq 1; then
	if ! (cd "$DESTDIR" && autoreconf -f); then
		abort "'autoreconf -f' failed."
	fi
	if ! (cd "$DESTDIR" && ./tools/make_requests); then
		abort "'./tools/make_requests' failed."
	fi
fi

# Success
exit 0