#!/bin/sh -efu

if [ -z "${__included_shell_signal-}" ]; then
__included_shell_signal=1

. shell-error
. shell-quote

__shell_signal_handlers=
# Set handler code whan any of the specified signals are received.
# Return code of handler function will be ignored. Special handlers is
# SIG_IGN and SIG_DFL (See signal(2)).
#
# Usage example:
# signal_handler 'echo $rc' TERM EXIT HUP
# signal_handler SIG_IGN TERM EXIT HUP
# signal_handler SIG_DFL TERM EXIT HUP
signal_handler() {
	local user_action real_action
	user_action="$1"
	shift

	__shell_signal_handler() {
		local s rc=$? sign="$1"
		local IFS=' 	
'
		eval set -- ${__shell_signal_handlers-}
		for s; do
			[ -n "${s##$sign:*}" ] ||
				eval ${s#$sign:} $rc ||:
		done
	}

	__shell_signal_append() {
		local s arg="$1"
		local IFS=' 	
'
		eval set -- ${__shell_signal_handlers-}
		for s; do
			[ "$s" != "$arg" ] || return 0
		done
		quote_shell_variable arg "$arg"
		__shell_signal_handlers="$__shell_signal_handlers \"$arg\""
	}

	__shell_signal_remove() {
		local s sign="$1"
		local IFS=' 	
'
		eval set -- ${__shell_signal_handlers-}
		__shell_signal_handlers=
		for s; do
			[ -n "${s##$sign:*}" ] ||
				continue
			quote_shell_variable s "$s"
			__shell_signal_handlers="$__shell_signal_handlers \"$s\""
		done
	}

	for sign; do
		sign="${sign#SIG}"

		case "$user_action" in
			SIG_IGN)
				__shell_signal_remove "$sign"
				real_action=:
				;;
			SIG_DFL)
				__shell_signal_remove "$sign"
				real_action=-
				;;
			*)
				__shell_signal_append "$sign:$user_action"
				real_action="__shell_signal_handler $sign"
				;;
		esac
		trap "$real_action" "$sign"
	done
}

# Set exit handler. Return code of handler function will be ignored.
#
# Usage example:
# exit_function() { echo "Exit with return code '$1'"; }
# set_cleanup_handler exit_function
__cleanup_handler_name=
set_cleanup_handler() {
	__cleanup_handler_name="${1-}"
	__cleanup_handler() {
		trap - EXIT
		[ -z "${__cleanup_handler_name-}" ] ||
			"$__cleanup_handler_name" "$1" ||:
		exit "$1"
	}
	signal_handler '__cleanup_handler $rc' EXIT
	signal_handler '__cleanup_handler   1' HUP PIPE INT QUIT TERM
}

# Remove exit handler.
#
# Usage example: unset_cleanup_handler
unset_cleanup_handler() {
	signal_handler SIG_DFL EXIT HUP PIPE INT QUIT TERM
	__cleanup_handler_name=
}

fi #__included_shell_signal
