#!/bin/sh -efu
### This file is covered by the GNU General Public License,
### which should be included with libshell as the file LICENSE.
### All copyright information are listed in the COPYING.

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

. shell-error
. shell-quote

__shell_signal_rc()
{
	return $1
}

__shell_signal_eval_rc()
{
	if __shell_signal_rc "$1"; then
		eval "$2"
	else
		eval "$2"
	fi
}

__shell_signal_handler()
{
    set -- "$?" "$1"
    while eval '[ $(($# - 2)) -lt "${__shell_signal_'$2':-0}" ]'; do
        eval 'set -- "$@" "$__shell_signal_'$2'_'$(($# - 2))'"'
    done
    eval 'shift 2; while [ $# -gt 0 ]; do __shell_signal_eval_rc '$1' "$1" ||:; shift; done; return '$1
}

### 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 $arg' TERM EXIT HUP
### signal_handler SIG_IGN     TERM EXIT HUP
### signal_handler SIG_DFL     TERM EXIT HUP
signal_handler()
{
	local action sign n=0
	action="$1"; shift

	for sign; do
		sign="${sign#SIG}"
		case "$action" in
			SIG_IGN)
				while eval "[ $n -lt \${__shell_signal_$sign:-0} ]"; do
					eval "unset __shell_signal_${sign}_$n"
					n=$(($n + 1))
				done
				eval "unset __shell_signal_$sign"
				trap : "$sign"
				;;
			SIG_DFL)
				while eval "[ $n -lt \${__shell_signal_$sign:-0} ]"; do
					eval "unset __shell_signal_${sign}_$n"
					n=$(($n + 1))
				done
				eval "unset __shell_signal_$sign"
				trap - "$sign"
				;;
			*)
				eval "n=\${__shell_signal_$sign:-0}"
				eval "__shell_signal_${sign}_$n=\"\$action\""
				eval "__shell_signal_${sign}=\$((\$n + 1))"
				# shellcheck disable=SC2064
				# Disable `Use single quotes, otherwise this expands now rather than when signalled.`
				# because $sign should be expanded.
				trap "__shell_signal_handler $sign" "$sign"
				;;
		esac
	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 $?' 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
