#!/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 "" ]; then
__included_shell_single=1

### shell-error
PROG="${PROG:-${0##*/}}"
message_syslog=
message_time=
message_time_format=
message()
{
	local arg='' prefix=''
	if [ -n "$message_syslog" ]; then
		[ ! -t 2 ] || arg=-s
		logger $arg -t "$PROG" "$*"
		return
	fi
	[ -z "$message_time" ] ||
		prefix="$(date +"${message_time_format:-[%Y-%m-%d %T]} " 2>/dev/null)" ||:
	printf %s\\n "${prefix}$PROG: $*" >&2
}
fatal()
{
	message "$@"
	exit 1
}
quiet="${quiet-}"
verbose="${verbose-}"
verbose()
{
	[ -n "$verbose" ] || return 0
	message "$@"
}

### shell-ip-address
readonly regex_byte='([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])'
readonly regex_ipaddr="$regex_byte(\.$regex_byte){3}"
readonly __regex_fbyte='([1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])'
readonly __regex_sbyte='([1]?[0-9][0-9]?|2[0-4][0-9]|25[0-4])'
readonly __regex_lbyte='([1]?[0-9][0-9]?|2[0-4][0-9]|25[0-4])'
readonly regex_ipv4="${__regex_fbyte}(\.${__regex_sbyte}){2}\.${__regex_lbyte}"
valid_ipv4()
{
	local ipaddr="$1"
	local i=0 byte
	byte="${ipaddr##*.}"
	ipaddr="${ipaddr%.$byte}"
	[ "$byte" -gt 0 ] && [ "$byte" -lt 255 ] 2>/dev/null ||
			return 1
	while [ $i -lt 3 ]; do
		byte="${ipaddr##*.}"
		[ "$byte" != "$ipaddr" ] ||
			break
		ipaddr="${ipaddr%.$byte}"
		[ "$byte" -ge 0 ] && [ "$byte" -lt 255 ] 2>/dev/null ||
			return 1
		i=$(($i+1))
	done
	[ $i -eq 2 ] &&
		[ "$byte" -ne 127 ] && [ "$byte" -gt 0 ] && [ "$byte" -lt 224 ] 2>/dev/null ||
		return 1
}
__ipv4_hex()
{
	[ -n "${1-}" ] ||
		return 2
	local IFS=.
	set -- $1
	local i=0
	for b; do
		[ "$b" -ge 0 ] && [ "$b" -le 255 ] 2>/dev/null ||
			return 2
		i=$(($i + 1))
	done
	[ "$i" -eq 4 ] ||
		return 2
	printf '0x'
	printf '%02x' "$@"
}
ipv4_ip_subnet()
{
	local ip net prefix
	ip="${1-}"; shift
	net="${1-}"; shift
	prefix="${net##*/}"
	[ -n "$prefix" ] && [ "$prefix" -ge 0 ] 2>/dev/null ||
		return 2
	local hex_addr hex_net hex_mask p
	hex_addr="$(__ipv4_hex "$ip")" &&
	hex_net="$(__ipv4_hex "${net%%/*}")" ||
		return 2
	p=$((0xFFFFFFFF))
	hex_mask="$(($p - ($p >> $prefix)))"
	[ "$(($hex_net & $hex_mask))" -eq "$(($hex_addr & $hex_mask))" ] ||
		return 1
}
ipv4_mask2prefix()
{
	local hex_mask
	hex_mask="$(__ipv4_hex "${1-}")" ||
		return 2
	local p i=0 prefix=''
	p=$((~$hex_mask & 0xFFFFFFFF))
	while [ "$p" -ne 0 ]; do
		p=$(($p >> 1 & 0xFFFFFFFF))
		i=$(($i + 1))
	done
	prefix=$((32 - $i))
	[ "$prefix" -ge 0 ] && [ "$prefix" -le 32 ] ||
		return 1
	echo "$prefix"
}
ipv4_prefix2mask()
{
	local len
	len="${1-}"
	[ "$len" -ge 0 ] && [ "$len" -le 32 ] 2>/dev/null ||
		return 1
	local position=$((0xFFFFFFFF))
	local mask=$(($position - ($position >> $len)))
	printf '%s.%s.%s.%s\n' \
	    "$(($mask >> 24 & 0xFF))" \
	    "$(($mask >> 16 & 0xFF))" \
	    "$(($mask >> 8  & 0xFF))" \
	    "$(($mask       & 0xFF))"
}

### shell-locks
#!/bin/bash -efu
# SPDX-License-Identifier: GPL-2.0-or-later
__shell_fd_lock()
{
	local fd="$1"; shift
	local fn="$1"; shift
	eval "exec $fd<\"$fn\""
	flock "$@" "$fd"
}
fd_rlock()   { __shell_fd_lock "$1" "$2" -s; }
fd_lock()    { __shell_fd_lock "$1" "$2" -x; }
fd_trylock() { __shell_fd_lock "$1" "$2" -n; }
fd_unlock()  { eval "exec $1<&-"; }
fd_is_locked()
{
	local fd=0
	while [ -e "/proc/self/fd/$fd" ]; do
		fd=$(( $fd + 1 ))
	done
	if fd_trylock "$fd" "$1"; then
		fd_unlock "$fd"
		return 1
	fi
	eval "exec $fd<&-"
	return 0
}

### shell-mail-address
if [ -n "${shell_mail_address_strict-}" ]; then
	readonly regex_cctld_active='(a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstwyz]|c[acdfghiklmnoruvxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[adefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklnrstwy]|qa|r[eosuw]|s[abcdeghiklmnrtuvyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|ye|z[amw])'
	readonly regex_cctld_reserved='(um|bl|eh|mf)'
	readonly regex_cctld_allocated='(bv|gb|pm|sj|so|yt)'
	readonly regex_cctld_phaseout='(tp|yu)'
	readonly regex_cctld_deleted='(cs|dd|zr)'
	readonly regex_gtld='(aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel)'
	regex_tld="($regex_gtld|$regex_cctld_active|$regex_cctld_reserved|$regex_cctld_allocated|$regex_cctld_phaseout)"
else
	regex_tld='([a-zA-Z]{2,4}|museum|travel)'
fi
readonly regex_domain="([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*)\.$regex_tld"
readonly regex_email="([_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*)@($regex_domain)"
valid_email()
{
	local email="$1"
	printf '%s' "$email" |
		grep -E -iqs "^$regex_email\$" ||
		return 1
}

### shell-process
daemon_write_pid()
{
	local pid='' pidfile
	pidfile="$1"
	if [ -z "${2-}" ]; then
		read -r pid < "$pidfile" ||:
		if [ -n "$pid" ] && [ -z "${pid##[0-9]*}" ]; then
			if kill -0 "$pid"; then
				verbose "Process with pid '$pid' still exists."
				return 1
			fi
		fi
	fi 2>/dev/null
	printf '%s\n' "$$" >"$pidfile"
}
daemon_close_fd()
{
	while [ $# -gt 0 ]; do
		eval "exec $1>&-"
		shift
	done
}
daemon_noclose=
daemon_nokill=
daemon_nolock=
daemon_err_file=
daemon_log_file=
daemon_pid_file=
daemon()
{
	local i fd
	if [ -z "${__shell_process_daemon-}" ]; then
		local sid=
		! type setsid >/dev/null 2>&1 ||
			sid=setsid
		__shell_process_daemon=1 $sid "$0" ${1:+"$@"} &
		exit 0
	fi
	if [ -z "${daemon_noclose-}" ]; then
		if [ -d /proc/self/fd ]; then
			# shellcheck disable=SC2035
			# Disable `Use ./*glob* or -- *glob* so names with dashes won't become options`
			# because printf does not regard the arguments as options.
			fd="$(set +f; cd /proc/self/fd; printf '%s ' *;)"
			fd="${fd#\* }"
			for i in $fd; do
				[ $i -lt 3 ] ||
					daemon_close_fd $i
			done
		else
			daemon_close_fd 3 4 5 6 7 8 9
		fi
	fi
	if [ -n "${daemon_pid_file-}" ]; then
		if [ -z "${daemon_nolock-}" ]; then
			fd="${daemon_lock_fd:-3}"
			eval "exec $fd<>$daemon_pid_file"
			type flock >/dev/null 2>&1 ||
				fatal "Unable to lock pid file without 'flock' utility."
			if ! flock -n $fd; then
				verbose "Another process has locked pidfile."
				return 1
			fi
		fi
		if ! daemon_write_pid "$daemon_pid_file" "${daemon_nokill-}"; then
			verbose "Unable to write pidfile."
			return 1
		fi
	fi
	exec 0</dev/null 1>>${daemon_log_file:-/dev/null} 2>>${daemon_err_file:-/dev/null}
	trap : HUP INT QUIT
	cd /
	umask 0
}

### shell-source
__shell_source_find()
{
	local r f IFS=:
	r="$1"; shift
	f="$1"; shift
	if [ -n "${f##*/*}" ]; then
		set -- ${PATH-}
		while [ "$#" -gt 0 ]; do
			if [ -e "$1/$f" ]; then
				f="$1/$f"
				break
			fi
			shift
		done
	fi
	[ -e "$f" ] || return 1
	eval "$r=\"\$f\""
}
source_if_exists()
{
	local v f
	f="$1";	shift
	! __shell_source_find v "$f" || [ ! -f "$v" ] || . "$v"
}
source_if_notempty()
{
	local v f
	f="$1"; shift
	! __shell_source_find v "$f" || [ ! -s "$v" ] || . "$v"
}
source_if_executable()
{
	local v f
	f="$1"; shift
	! __shell_source_find v "$f" || [ ! -x "$v" ] || . "$v"
}

### shell-string
fill_mask()
{
__fill_mask()
{
	local m=
	while :; do
		case $((${#1} - ${#m})) in
			0) break ;;
			1) m="$m?" ;;
			2) m="$m??" ;;
			3) m="$m???" ;;
			4) m="$m????" ;;
			5) m="$m?????" ;;
			6) m="$m??????" ;;
			7) m="$m???????" ;;
			8) m="$m????????" ;;
			9) m="$m?????????" ;;
			*) m="$m??????????" ;;
		esac
	done
	__fill_masko="${m#$2}"
}
	local __fill_masko
	__fill_mask "$2" "${3:-?}"
	unset -f __fill_mask
	eval "$1=\$__fill_masko"
}

### shell-terminfo
COLUMNS=80
LINES=25
color_black=7
color_blue=7
color_green=7
color_cyan=7
color_red=7
color_magenta=7
color_yellow=7
color_white=7
__terminfo_setup_caps()
{
	set \
		setbg:setab \
		setbg:setb \
		setfg:setaf \
		setfg:setf \
		bold:bold \
		sitm:sitm \
		smul:smul \
		rev:rev \
		hpa:hpa \
		vpa:vpa \
		ritm:ritm \
		rmul:rmul \
		op:op \
		sgr0:sgr0 \
	;
	local cap_pair var cap
	for cap_pair; do
		var="${cap_pair%:*}"
		eval "__terminfo_cap_$var=''"
	done
	for cap_pair; do
		var="${cap_pair%:*}"
		cap="${cap_pair#*:}"
		eval "
		__terminfo_cap_$var=\"\${__terminfo_cap_$var-}\";
		! tput $cap >/dev/null 2>&1 ||
			__terminfo_cap_$var='$cap';
		[ -n \"\$__terminfo_cap_$var\" ] ||
			verbose \"Capability '$cap' is not defined for this terminal.\""
	done
}
__terminfo_setup_colors()
{
	local order name i=0
	[ "$__terminfo_cap_setfg" = 'setf' ] &&
		order='black blue green cyan red magenta yellow white' ||
		order='black red green yellow blue magenta cyan white'
	for name in $order; do
		eval "color_$name=$i"
		i=$(($i + 1))
	done
}
# shellcheck disable=SC2120
terminfo_init()
{
	[ -z "${__terminfo_init-}" ] || [ "${1-}" = force ] ||
		return 0
	type tput >/dev/null 2>&1 ||
		fatal "Unable to find \`tput' utility."
	[ -n "${TERM-}" ] || TERM=dumb
	export TERM
	local cols rows
	cols="$(tput cols)"  && export COLUMNS="$cols" || return
	rows="$(tput lines)" && export LINES="$rows"   || return
	__terminfo_setup_caps
	__terminfo_setup_colors
	__terminfo_init=1
}
terminfo_color_pattern()
{
	local c ctype='fg' color
	local color_bg='' color_fg='' bold='' italic='' uline='' reverse=''
	for c in $2; do
		case "$c" in
			fg|foreground)
				ctype='fg'
				;;
			bg|background)
				ctype='bg'
				;;
			rev|reverse)
				reverse=1
				;;
			b|bold)
				bold=1
				;;
			i|italic)
				italic=1
				;;
			u|underline)
				uline=1
				;;
			black|blue|green|cyan|red|magenta|yellow|white)
				eval "[ -z \"\${__terminfo_cap_set$ctype-}\" ] || color_$ctype=\"\$color_$c\""
				;;
			*)
				fatal "Unknown color: $c"
				;;
		esac
	done
	case "$1" in
		b|begin)
			tput -S <<EOF
${reverse:+$__terminfo_cap_rev
}${bold:+$__terminfo_cap_bold
}${italic:+$__terminfo_cap_sitm
}${uline:+$__terminfo_cap_smul
}${color_fg:+$__terminfo_cap_setfg $color_fg
}${color_bg:+$__terminfo_cap_setbg $color_bg
}
EOF
			;;
		e|end)
			tput -S <<EOF
${italic:+$__terminfo_cap_ritm
}${uline:+$__terminfo_cap_rmul
}${__terminfo_cap_op:+$__terminfo_cap_op
}${__terminfo_cap_sgr0:+$__terminfo_cap_sgr0
}
EOF
			;;
		*)
			fatal "Unknown type: $1"
			;;
	esac
}
terminfo_col()
{
	# shellcheck disable=SC2119
	terminfo_init
	if [ -n "${COLUMNS-}" ] && [ "$1" -ge "${COLUMNS:-0}" ]; then
		message "value must be less than $COLUMNS"
		return 1
	fi
	[ -n "${__terminfo_cap_hpa-}" ] ||
		message "Capability 'hpa' is not defined for this terminal."
	tput "$__terminfo_cap_hpa" "$1"
}
terminfo_row()
{
	# shellcheck disable=SC2119
	terminfo_init
	[ -n "${__terminfo_cap_vpa-}" ] ||
		message "Capability 'vpa' is not defined for this terminal."
	tput "$__terminfo_cap_vpa" "$1"
}
color_text()
{
	# shellcheck disable=SC2119
	terminfo_init
	terminfo_color_pattern b "$2" || return
	printf '%s' "$1"
	terminfo_color_pattern e "$2" || return
}
color_message()
{
	color_text "$@" || return
	printf '\n'
}

### shell-unittest
TESTCASES="${TESTCASES-}"
unittest_use_color="${unittest_use_color-}"
unittest_show_condition="${unittest_show_condition-}"
unittest_hide_successful="${unittest_hide_successful-}"
setUp() { :; }
tearDown() { :; }
setUpTests() { :; }
tearDownTests() { :; }
__shell_unit_tests=
appendTests()
{
	while [ "$#" -gt 0 ]; do
		__shell_unit_tests="$__shell_unit_tests
$1"
		shift
	done
}
registerTests()
{
	local l
	l="$(sed -ne 's/^\([[:alnum:]_]\+\)().*[[:space:]]*#[[:space:]]*UnitTest/\1/p' "${1:-$0}")"
	[ -z "$l" ] || appendTests $l
}
shouldSkip()
{
	exit 2
}
assertTrue()
{
	local comment='' condition
	[ "$#" -lt 2 ] ||
		{ comment="$1"; shift; }
	condition="$1"; shift
	[ -z "$unittest_show_condition" ] ||
		comment="${comment:+$comment }($condition) == false"
	if [ -n "${condition##*[!0-9\-]*}" ]; then
		[ $condition -ne 0 ] ||
			return 0
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
	if ! ( eval "$condition" ) >/dev/null; then
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
}
assertFalse()
{
	local comment='' condition
	[ "$#" -lt 2 ] ||
		{ comment="$1"; shift; }
	condition="$1"; shift
	[ -z "$unittest_show_condition" ] ||
		comment="${comment:+$comment }($condition) == true"
	if [ -n "${condition##*[!0-9\-]*}" ]; then
		[ $condition -eq 0 ] ||
			return 0
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
	if ( eval "$condition" ) >/dev/null; then
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
}
assertEquals()
{
	local comment='' expected actual
	[ "$#" -lt 3 ] ||
		{ comment="$1"; shift; }
	expected="$1"; shift
	actual="$1"; shift
	if [ "$expected" != "$actual" ]; then
		[ -z "$unittest_show_condition" ] ||
			comment="${comment:+$comment }($expected) != ($actual)"
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
}
assertSame()
{
	assertEquals "${@-}"
}
assertNotEquals()
{
	local comment='' expected actual
	[ "$#" -lt 3 ] ||
		{ comment="$1"; shift; }
	expected="$1"; shift
	actual="$1"; shift
	if [ "$expected" = "$actual" ]; then
		[ -z "$unittest_show_condition" ] ||
			comment="${comment:+$comment }($expected) == ($actual)"
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
}
assertNotSame()
{
	assertNotEquals "${@-}"
}
assertNull()
{
	local comment='' value
	[ "$#" -lt 2 ] ||
		{ comment="$1"; shift; }
	value="$1"; shift
	if [ -n "$value" ]; then
		[ -z "$unittest_show_condition" ] ||
			comment="${comment:+$comment }($value) == ''"
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
}
assertNotNull()
{
	local comment='' value
	[ "$#" -lt 2 ] ||
		{ comment="$1"; shift; }
	value="$1"; shift
	if [ -z "$value" ]; then
		[ -z "$unittest_show_condition" ] ||
			comment="${comment:+$comment }($value) != ''"
		[ -z "$comment" ] ||
			printf '%s' "$comment"
		exit 1
	fi
}
messageTest()
{
	__show()
	{
		unset -f __show
		local colors="$1"; shift
		if [ -z "$unittest_use_color" ]; then
			"$@"
			return 0
		fi
		color_text "$("$@")" "$colors"
		return 0
	}
	case "$3" in
		0)
			[ -z "$unittest_hide_successful" ] ||
				return 0
			__show 'green'  printf '[done]' ;;
		1)	__show 'red'    printf '[FAIL]' ;;
		2)	__show 'yellow' printf '[skip]' ;;
		*)	printf '[status=%s]' $3 ;;
	esac
	printf ' (%s) %s\n' "$1" "$2"
}
showSummary()
{
	if [ "$total" -eq 0 ]; then
		message "Nothing to do"
		return
	fi
	printf '\n'
	printf 'tests passed:  %6d %3d%%\n' "$passed" "$((($passed*100)/$total))"
	printf 'tests failed:  %6d %3d%%\n' "$failed" "$((($failed*100)/$total))"
	printf 'tests skipped: %6d %3d%%\n' "$skipped" "$((($skipped*100)/$total))"
	printf 'tests total:   %6d\n\n' "$total"
}
runUnitTests()
{
	need_test()
	{
		local __="$1"
		shift
		[ "$#" -gt 0 ] ||
			return 0
		while [ "$#" -gt 0 ]; do
			[ "$1" != "$__" ] ||
				return 0
			shift
		done
		return 1
	}
	run_test()
	{
		if [ -n "${TESTTRACE-}" ]; then
			printf '\n' >&2
			set -x
		fi
		"$1"
	}
	run_or_exit()
	{
		"$@" || fatal "$1() fail rc=$?"
	}
	[ -z "$unittest_use_color" ] || . shell-terminfo
	run_or_exit setUpTests
	local IFS=' 	
'
	__shell_unit_tests="$(printf '%s\n' "$__shell_unit_tests" |sort -u)"
	set -- ${__shell_unit_tests-}
	local retval=0 rc passed=0 failed=0 skipped=0 total="$#"
	while [ "$#" -gt 0 ]; do
		if ! need_test "$1" ${TESTCASES-}; then
			shift
			continue
		fi
		run_or_exit setUp
		rc=0
		msg="$(run_test "$1")" || rc=$?
		case "$rc" in
			0) passed=$(($passed+1)) ;;
			1) failed=$(($failed+1)); retval=1; ;;
			2) skipped=$(($skipped+1)) ;;
			*)
				{
					printf '\n'
					printf 'FATAL: Unexpected return code.\n'
					printf '\n'
					printf '%s\n' "Testcase '$1' ended with an unexpected return code: rc=$rc"
					printf '%s\n' "Check its correctness. Return code must be success=0, fail=1, skipped=2."
				} >&2
				retval=1
				break
				;;
		esac
		run_or_exit messageTest "$1" "$msg" "$rc"
		run_or_exit tearDown
		shift
	done
	run_or_exit showSummary
	run_or_exit tearDownTests
	return $retval
}

### shell-var
shell_var_is_number()
{
	[ -n "${1##0*}" ] && [ -n "${1##*[!0-9]*}" ] && [ "$1" -gt 0 ] 2>/dev/null ||
		return 1
}
shell_var_is_yes()
{
	[ "$#" -eq 1 ] ||
		fatal "Usage: shell_var_yes value"
	case "$1" in
		[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|[Yy]|1) return 0 ;;
	esac
	return 1
}
shell_var_is_no()
{
	[ "$#" -eq 1 ] ||
		fatal "Usage: shell_var_no value"
	case "$1" in
		[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|[Nn]|0) return 0 ;;
	esac
	return 1
}
shell_var_trim()
{
	[ "$#" -eq 2 ] ||
		fatal "Usage: shell_var_trim varname value"
__shell_var_trim()
{
	unset -f __shell_var_trim
	local r="$1" space=' 	
'
	while [ -n "$r" ] && [ -z "${r##[$space]*[$space]}" ]; do r="${r%?}"; r="${r#?}"; done
	while [ -n "$r" ] && [ -z "${r##*[$space]}" ]; do r="${r%?}"; done
	while [ -n "$r" ] && [ -z "${r%%[$space]*}" ]; do r="${r#?}"; done
	__shell_var_trimo="$r"
}
	local __shell_var_trimo=
	__shell_var_trim "$2"
	eval "$1=\"\$__shell_var_trimo\""
}
shell_var_unquote()
{
	[ "$#" -eq 2 ] ||
		fatal "Usage: shell_var_unquote varname value"
__shell_var_unquote()
{
	local o="$1"
	if [ -z "${o##*\'}${o%%\'*}" ]; then
		o="${o#\'}" o="${o%\'}"
	elif [ -z "${o##*\"}${o%%\"*}" ]; then
		o="${o#\"}" o="${o%\"}"
	fi
	__shell_var_unquoteo="$o"
}
	local __shell_var_unquoteo
	__shell_var_unquote "$2"
	unset -f __shell_var_unquote
	eval "$1=\"\$__shell_var_unquoteo\""
}

### shell-version
libshell_vmajor=0
libshell_vminor=4
libshell_vpatch=13
libshell_version=4
__export_compatibility_string_quote_remove=1

### shell-args
opt_check_read()
{
	local value
	[ -r "$2" ] &&
	value="$(readlink -fv -- "$2")" ||
		fatal "$1: $2: file not available."
	printf %s "$value"
}
opt_check_exec()
{
	local value
	[ -f "$2" ] && [ -x "$2" ] &&
	value="$(readlink -fv -- "$2")" ||
		fatal "$1: $2: file not executable."
	printf %s "$value"
}
opt_check_dir()
{
	local value
	[ -d "$2" ] && [ -x "$2" ] &&
	value="$(readlink -fv -- "$2")" ||
		fatal "$1: $2: directory not available."
	printf %s "$value"
}
opt_check_number()
{
	shell_var_is_number "$2" ||
		fatal "$1: $2: invalid number."
	printf %s "$2"
}
show_usage()
{
	[ -z "$*" ] || message "$*"
	echo "Try \`$PROG --help' for more information." >&2
	exit 1
}
show_help()
{
	fatal "show_help(): Undefined function"
}
print_version()
{
	fatal "print_version() Undefined function"
}
readonly getopt_common_opts="q,v,V,h"
readonly getopt_common_longopts="quiet,verbose,version,help"
parse_common_option()
{
	case "$1" in
		-h|--help) show_help
			;;
		-q|--quiet) quiet=-q; verbose=
			;;
		-v|--verbose) verbose=-v; quiet=
			;;
		-V|--version) print_version "$PROG"
			;;
		*) fatal "Unrecognized option: $1"
			;;
	esac
}

### shell-cmdline
cmdline_foreach()
{
	local l h c='' m=''
	l="$1"; shift
	h="$1"; shift
	__is_set() {
		[ $(( $1 & $2 )) -eq $2 ]
	}
	fill_mask m "$l"
	local state=$((0))
	local VALUE=$((2))
	local EQUAL=$((4))
	local QUOTE=$((16))
	local n='' v='' f=1
	while [ -n "$l" ]; do
		c="${l%$m}"
		case "$c" in
			'"')
				__is_set $state $QUOTE &&
					state=$(($state ^ $QUOTE)) ||
					state=$(($state | $QUOTE))
				;;
			' ')
				if __is_set $state $QUOTE; then
					v="$v$c"
				else
					f=
					__is_set $state $EQUAL ||
						{ v=1; f=1; }
					$h "$n" "$v" "$f" ||
						break
					n='' v='' f=''
					state=$((0))
				fi
				;;
			'=')
				! __is_set $state $VALUE ||
					v="$v$c"
				state=$(($state | $VALUE | $EQUAL))
				;;
			*)
				if ! __is_set $state $VALUE; then
					[ "$c" != '-' ] || c='_'
					n="$n$c"
				else
					v="$v$c"
				fi
				;;
		esac
		l="${l#?}"
		m="${m#?}"
	done
	if [ -n "$n" ]; then
		f=
		__is_set $state $EQUAL ||
			{ v=1; f=1; }
		$h "$n" "$v" "$f" ||:
	fi
	unset -f __is_set
}
cmdline_get()
{
	local __cmdline __retv __getn
	__retv="$1"; shift
	__getn="$1"; shift
	if [ "$#" -eq 0 ]; then
		read -r __cmdline < /proc/cmdline
	else
		__cmdline="$1"
	fi
	local c m l="$__getn"
	__getn=
	fill_mask m "$l"
	while [ -n "$l" ]; do
		c="${l%$m}"
		[ "$c" != '-' ] || c='_'
		__getn="$__getn$c"
		l="${l#?}"
		m="${m#?}"
	done
	unset c m l
	__getval()
	{
		[ "$1" != "$__getn" ] || eval "$__retv=\"\$2\""
	}
	cmdline_foreach "$__cmdline" __getval
	unset -f __getval
}

### shell-git-config
GIT_CONFIG_GET_RAW=
GIT_CONFIG_INCLUDE=1
__git_config_git_topdir()
{
	local __p="$2"
	while [ -n "$__p" ]; do
		[ ! -d "$__p/.git" ] ||
			break
		__p="${__p%/*}"
	done
	eval "$1=\"\$__p\""
}
__git_config_lc()
{
	local __lc="$2"
	[ -n "${2##*[A-Z]*}" ] ||
		__lc="$(printf '%s' "$2" |tr '[:upper:]' '[:lower:]')"
	eval "$1=\"\$__lc\""
}
# Parse incoming argument into pieces
__git_config_split()
{
	[ -z "${1##*.*}" ] ||
		fatal " key does not contain a section: $1"
	local sl nl
	__git_config_section="${1%%.*}"
	[ -n "${__git_config_section##*[!A-Za-z0-9-]*}" ] ||
		fatal "bad section name: $__git_config_section"
	__git_config_lc sl "$__git_config_section"
	__git_config_name="${1##*.}"
	[ -n "${__git_config_name##*[!A-Za-z0-9-]*}" ] ||
		fatal "bad variable name: $__git_config_name"
	__git_config_lc nl "$__git_config_name"
	__git_config_subsection="${1#*.}"
	[ "$__git_config_subsection" != "$__git_config_name" ] &&
		__git_config_subsection="${__git_config_subsection%.*}" ||
		__git_config_subsection=
	__git_config_location="$sl${__git_config_subsection:+.$__git_config_subsection}"
	__git_config_fullpath="$__git_config_location.$nl"
}
__git_config_fullpath()
{
	local __git_config_section __git_config_name __git_config_subsection
	__git_config_split "$1"
}
__git_config_value()
{
	local dq='' bq='' c='' m='' l="$1"
	fill_mask m "$l"
	value=
	while [ -n "$l" ]; do
		c="${l%$m}"
		l="${l#?}"
		m="${m#?}"
		case "$c" in
			\\)
				if [ -z "$bq" ]; then
					bq=1
					c=
				else
					bq=
				fi
				;;
			\")
				if [ -z "$bq" ]; then
					[ -z "$dq" ] && dq=1 || dq=
					c=
				else
					bq=
				fi
				;;
			b|n|t)
				if [ -n "$bq" ]; then
					bq=
					# shellcheck disable=SC2059
					# Disable `Don't use variables in the printf format string`
					# because we actually want to interpret data as a format string.
					c="$(printf "\\$c#")"
					c="${c%#}"
				fi
				;;
			*)
				bq=
				;;
		esac
		value="$value$c"
	done
	[ -z "$dq" ] ||
		fatal "bad config file line $nline in $fn"
}
git_config_handler() { :; }
git_config_parse_file()
{
	local fn="$1" name value section='' subsection='' section_lower='' name_lower='' location='' line oline nline=0 eof=''
	__git_config_parse_section()
	{
		local line="$1" invalid='[!A-Za-z0-9-.]'
		if [ -n "$section" ]; then
			location="$section_lower${subsection:+.$subsection}"
			git_config_handler 'section-end'
		fi
		section="$line"
		subsection=
		if [ -z "${line##*[ 	]*}" ]; then
			section="${line%%[ 	]*}"
			subsection="${line#*[ 	]\"}"
			subsection="${subsection%\"}"
			invalid="[!A-Za-z0-9-]"
		fi
		[ -n "${section##*$invalid*}" ] ||
			fatal "bad config file line $nline in $fn"
		__git_config_lc section_lower "$section"
		location="$section_lower${subsection:+.$subsection}"
		git_config_handler 'section-start'
	}
	__git_config_parse_variable()
	{
		shell_var_trim name "${1%%=*}"
		[ -z "${1##*=*}" ] &&
			shell_var_trim value "${1#*=}" ||
			value='true'
		shell_var_unquote value "$value"
		[ -n "${GIT_CONFIG_GET_RAW-}" ] ||
			__git_config_value "$value"
		__git_config_lc name_lower "$name"
		location="$section_lower.${subsection:+$subsection.}$name_lower"
		git_config_handler 'variable'
	}
	__git_config_expend_path()
	{
		local __i="$2"
		[ -n "${__i##./*}" ] || [ "$fn" = "${fn%/*}" ] ||
			__i="${fn%/*}/${__i#./}"
		[ -n "${__i##\~/*}" ] ||
			__i="$HOME/${__i#\~/}"
		[ -n "${__i##\~*}" ] ||
			fatal "expression isn't supported at line $nline in $fn"
		eval "$1=\"\$__i\""
	}
	__git_config_parse_include_or_if()
	{
		local i='' gitdir='' pattern=''
		[ -z "${2-}" ] ||
			case "$2" in
				'gitdir:'*)
					gitdir="${GIT_DIR-}"
					if [ -z "$gitdir" ]; then
						__git_config_git_topdir gitdir "${fn%/*}"
						[ -z "$gitdir" ] ||
							gitdir="$gitdir/.git"
					fi
					__git_config_expend_path pattern "${2#gitdir:}"
					[ -n "${pattern##*/}" ] && [ -n "${pattern##*/\*\*}" ] ||
						pattern="${pattern%/*}/*"
					[ -n "${pattern##\*\*/*}" ] ||
						pattern="*/${pattern#*/}"
					[ -z "${pattern##/*}" ] || [ -z "${pattern##\**}" ] ||
						pattern="*/$pattern"
					[ -z "${gitdir##$pattern}" ] ||
						return 0
					;;
				*)
					fatal "condition is not supported: $2"
					;;
			esac
		__git_config_expend_path i "$1"
		[ ! -e "$i" ] ||
			git_config_parse_file "$i"
	}
	__git_config_parse_include()
	{
		[ "$location" != 'include.path' ] ||
			__git_config_parse_include_or_if "$1"
	}
	__git_config_parse_includeif()
	{
		[ -n "${location##includeif.*.path}" ] || [ -z "$subsection" ] ||
			__git_config_parse_include_or_if "$1" "$subsection"
	}
	oline=
	while [ -z "$eof" ]; do
		nline=$(($nline + 1))
		IFS= read -r line || eof=1
		line="$oline$line"
		oline=
		case "$line" in
			'')
				;;
			*\\)
				oline="$line"
				;;
			'#'*|';'*)
				git_config_handler 'comment'
				;;
			'['*']'[' 	']*[!' 	']*)
				fatal "expression isn't supported at line $nline in $fn"
				;;
			'['*']')
				line="${line#\[}"
				line="${line%\]}"
				__git_config_parse_section "$line"
				;;
			*)
				__git_config_parse_variable "$line"
				if [ -n "$GIT_CONFIG_INCLUDE" ]; then
					__git_config_parse_include "$value"
					__git_config_parse_includeif "$value"
				fi
				;;
		esac
	done < "$fn"
	[ -n "$section" ] ||
		return 0
	location="$section_lower${subsection:+.$subsection}"
	git_config_handler 'section-end'
}
git_config_location_exists()
{
	local __git_config_location_exists=1 __git_config_fullpath __git_config_location
	git_config_handler()
	{
		[ "$__git_config_fullpath" != "$location" ] ||
			__git_config_location_exists=0
	}
	__git_config_fullpath "$2"
	git_config_parse_file "$1"
	return $__git_config_location_exists
}
git_config_get()
{
	local __git_config_v='' __git_config_fullpath __git_config_location
	git_config_handler()
	{
		[ "$1" != 'variable' ] || [ "$__git_config_fullpath" != "$location" ] ||
			__git_config_v="$value"
	}
	__git_config_fullpath "$3"
	git_config_parse_file "$2"
	eval "$1=\"\$__git_config_v\""
}
git_config_count()
{
	local __git_config_v=0 __git_config_fullpath __git_config_location
	git_config_handler()
	{
		[ "$1" != 'variable' ] || [ "$__git_config_fullpath" != "$location" ] ||
			__git_config_v=$(($__git_config_v + 1))
	}
	__git_config_fullpath "$3"
	git_config_parse_file "$2"
	eval "$1=\"\$__git_config_v\""
}
git_config_list()
{
	local __git_config_fullpath='' __git_config_location=''
	git_config_handler()
	{
		[ "$1" = 'variable' ] ||
			return 0
		if [ -n "$__git_config_location" ]; then
			[ "$__git_config_fullpath" != "$location" ] ||
				printf '%s\n' "$value"
		else
			printf '%s=%s\n' "$location" "$value"
		fi
	}
	[ -z "${2-}" ] ||
		__git_config_fullpath "$2"
	git_config_parse_file "$1"
}
git_config_parse()
{
	git_config_handler()
	{
		[ "$1" = 'variable' ] ||
			return 0
		printf '%s\t%s\n' "$location" "$value"
	}
	git_config_parse_file "$1"
}
git_config_append()
{
	local GIT_CONFIG_INCLUDE='' GIT_CONFIG_GET_RAW=1
	local __git_config_section __git_config_name __git_config_subsection __git_config_fullpath __git_config_location
	local __git_config_nvalue="$3"
	local __git_config_state=0 fn
	[ -f "$1" ] || :> "$1"
	__git_config_split "$2"
	git_config_handler()
	{
		case "$1" in
			comment)
				printf '%s\n' "$line"
				;;
			variable)
				printf '\t%s = %s\n' "$name" "$value"
				if [ "$__git_config_fullpath" = "$location" ] && [ $__git_config_state != 1 ]; then
					printf '\t%s = %s\n' "$__git_config_name" "$__git_config_nvalue"
					__git_config_state=1
				fi
				;;
			section-start)
				printf '[%s]\n' "$section${subsection:+ \"$subsection\"}"
				;;
			section-end)
				if [ "$__git_config_location" = "$location" ] && [ $__git_config_state != 1 ]; then
					printf '\t%s = %s\n' "$__git_config_name" "$__git_config_nvalue"
					__git_config_state=1
				fi
				;;
		esac
	}
	fn="$(mktemp "$1.XXXXXX")"
	git_config_parse_file "$1" > "$fn"
	if [ $__git_config_state -eq 0 ]; then
		printf '[%s]\n\t%s = %s\n' \
			"$__git_config_section${__git_config_subsection:+ \"$__git_config_subsection\"}" \
			"$__git_config_name" "$__git_config_nvalue" >> "$1"
		rm -f -- "$fn"
	else
		mv -f -- "$fn" "$1"
	fi
}
git_config_set()
{
	local GIT_CONFIG_INCLUDE='' GIT_CONFIG_GET_RAW=1
	local __git_config_section __git_config_name __git_config_subsection __git_config_fullpath __git_config_location
	local __git_config_nvalue="$3" __git_config_ovalue=''
	local __git_config_state=0 fn
	[ -f "$1" ] || :> "$1"
	__git_config_split "$2"
	git_config_get __git_config_ovalue "$1" "$2"
	git_config_handler()
	{
		case "$1" in
			comment)
				printf '%s\n' "$line"
				;;
			variable)
				if [ "$__git_config_fullpath" = "$location" ] && [ -n "$__git_config_ovalue" ]; then
					if [ "$__git_config_ovalue" = "$value" ]; then
						printf '\t%s = %s\n' "$__git_config_name" "$__git_config_nvalue"
						__git_config_state=1
					fi
				else
					printf '\t%s = %s\n' "$name" "$value"
				fi
				;;
			section-start)
				printf '[%s]\n' "$section${subsection:+ \"$subsection\"}"
				;;
			section-end)
				if [ "$__git_config_location" = "$location" ] && [ $__git_config_state != 1 ]; then
					printf '\t%s = %s\n' "$__git_config_name" "$__git_config_nvalue"
					__git_config_state=1
				fi
				;;
		esac
	}
	fn="$(mktemp "$1.XXXXXX")"
	git_config_parse_file "$1" > "$fn"
	if [ $__git_config_state -eq 0 ]; then
		printf '[%s]\n\t%s = %s\n' \
			"$__git_config_section${__git_config_subsection:+ \"$__git_config_subsection\"}" \
			"$__git_config_name" "$__git_config_nvalue" >> "$1"
		rm -f -- "$fn"
	else
		mv -f -- "$fn" "$1"
	fi
}
git_config_unset()
{
	local GIT_CONFIG_INCLUDE='' GIT_CONFIG_GET_RAW=1
	local __git_config_section __git_config_name __git_config_subsection __git_config_fullpath __git_config_location
	local __git_config_ovalue="${3-}"
	local fn
	[ -f "$1" ] || :> "$1"
	__git_config_split "$2"
	git_config_handler()
	{
		case "$1" in
			comment)
				printf '%s\n' "$line"
				;;
			variable)
				if [ "$__git_config_fullpath" = "$location" ]; then
					[ -z "$__git_config_ovalue" ] || [ "$__git_config_ovalue" = "$value" ] ||
						printf '\t%s = %s\n' "$name" "$value"
				else
					printf '\t%s = %s\n' "$name" "$value"
				fi
				;;
			section-start)
				[ "$__git_config_fullpath" = "$location" ] ||
					printf '[%s]\n' "$section${subsection:+ \"$subsection\"}"
				;;
		esac
	}
	fn="$(mktemp "$1.XXXXXX")"
	git_config_parse_file "$1" > "$fn"
	mv -f -- "$fn" "$1"
}
__var_append()
{
	local n
	eval "n=\${$1:-0}"
	eval "${1}_${n}_n=\"\$2\""
	eval "${1}_${n}_v=\"\$3\""
	eval "$1=$(($n+1))"
}
__arr_append()
{
	local n
	eval "n=\${$2:-0}"
	eval "${2}_${n}=\"\$3\""
	eval "$2=$(($n+1))"
	eval "$1=$n"
}
__arr_find()
{
	local i=0 n='' v=''
	eval "$1="
	eval "n=\${$2:-0}"
	while [ "$i" -lt "$n" ]; do
		eval "v=\"\${${2}_${i}}\""
		if [ "$v" = "$3" ]; then
			eval "$1=$i"
			return
		fi
		i=$(($i+1))
	done
}
git_config_env()
{
	s=0
	local idx='' sidx=''
	git_config_handler()
	{
		case "$1" in
			section-start)
				case "$section_lower" in
					include|includeif) return ;;
				esac
				__arr_find idx s "$section_lower"
				[ -n "$idx" ] ||
					__arr_append idx s "$section_lower"
				if [ -n "$subsection" ]; then
					__arr_find sidx "ss_$idx" "$subsection"
					[ -n "$sidx" ] ||
						__arr_append sidx "ss_$idx" "$subsection"
				else
					eval "ss_$idx=\${ss_$idx:-0}"
					sidx=
				fi
				;;
			variable)
				[ -n "$idx" ] ||
					fatal "variable outside of section"
				__var_append "v_${idx}${sidx:+_$sidx}_x" "$name_lower" "$value"
				;;
		esac
	}
	git_config_parse_file "$1"
}
git_config_get_var()
{
	local __git_config_get_var_ret="$1" __git_config_get_var_v=''
	__git_config_get_var()
	{
		local n='' v='' i=0 idx='' sidx=''
		__arr_find idx s "$2"
		[ "${#idx}" != 0 ] ||
			return 0
		if [ "${#3}" != 0 ]; then
			eval "n=\"\$ss_$idx\""
			[ "${#n}" != 0 ] && [ "$n" != 0 ] &&
				__arr_find sidx "ss_$idx" "$3" ||
				return 0
		fi
		eval "n=\"\${v_$idx${sidx:+_$sidx}_x:-0}\""
		while [ "$i" -lt "$n" ]; do
			eval "v=\"\$v_$idx${sidx:+_$sidx}_x_${i}_n\""
			if [ "$v" = "$4" ]; then
				eval "v=\"\$v_$idx${sidx:+_$sidx}_x_${i}_v\""
				case "${5-}" in
					first)
						eval "__git_config_get_var_v=\"\$v\""
						return
						;;
					all=*)
						eval "__git_config_get_var_v=\"\${__git_config_get_var_v:+\${__git_config_get_var_v}${5#all=}}\$v\""
						;;
					''|last)
						eval "__git_config_get_var_v=\"\$v\""
						;;
				esac
			fi
			i=$(($i+1))
		done
	}
	__git_config_get_var "$@"
	eval "$__git_config_get_var_ret=\"\$__git_config_get_var_v\""
}
git_config_foreach_handler()
{
	printf '%s=%s\n' "$1" "$2"
}
git_config_foreach()
{
	local __git_config_foreach_name="${1-}"
	local __git_config_foreach_handler="${2:-git_config_foreach_handler}"
	__arr_foreach()
	{
		local i=0 x=0 n='' v=''
		eval "set -- \"\${$1:-0}\" \"\$@\""
		while [ "$i" -lt "$1" ]; do
			eval "n=\"\${${2}_${i}_n}\""
			eval "v=\"\${${2}_${i}_v}\""
			if [ -z "$__git_config_foreach_name" ] || [ "$__git_config_foreach_name" = "${3:+$3.}$n" ]; then
				"$__git_config_foreach_handler" "${3:+$3.}$n" "$v"
			fi
			i=$(($i+1))
		done
	}
	local i=0 j=0 ss section subsection
	while [ "$i" -lt "${s:-0}" ]; do
		eval "section=\"\$s_${i}\""
		__arr_foreach "v_${i}_x" "$section"
		eval "ss=\"\${ss_${i}:-0}\""
		j=0
		while [ "$j" -lt "$ss" ]; do
			eval "subsection=\"\$ss_${i}_${j}\""
			__arr_foreach "v_${i}_${j}_x" "$section.$subsection"
			j=$(($j+1))
		done
		i=$(($i+1))
	done
}
git_config_get_subsections_handler() { :; }
git_config_get_subsections()
{
	local __git_config_get_subsections_idx=
	__git_config_get_subsections_idx()
	{
		local n='' v='' i=0
		eval "n=\${s:-0}"
		while [ "$i" -lt "$n" ]; do
			eval "v=\"\${s_${i}}\""
			if [ "$v" = "$1" ]; then
				__git_config_get_subsections_idx=$i
				return 0
			fi
			i=$(($i+1))
		done
		return 1
	}
	__git_config_get_subsections_idx "$1" || return 0
	__git_config_get_subsections_idx()
	{
		__git_config_get_subsections_idx=0
		while [ "$__git_config_get_subsections_idx" -lt "$2" ]; do
			eval "git_config_get_subsections_handler \"\${ss_${1}_${__git_config_get_subsections_idx}}\""
			__git_config_get_subsections_idx=$(($__git_config_get_subsections_idx+1))
		done
	}
	eval "__git_config_get_subsections_idx \"$__git_config_get_subsections_idx\" \"\$ss_$__git_config_get_subsections_idx\""
}

### shell-ini-config
shell_ini_config_comment='#'
shell_ini_config_prefix='	'
__ini_config_print()
{
	local p="$1"; shift
	printf '%s%s\n' "${p:+${shell_ini_config_prefix-}}" "$@"
}
ini_config_get()
{
	local fn section var sect='' str eof='' n v
	fn="$1" section="$2" var="$3"
	if [ ! -e "$fn" ]; then
		message "No such file or directory: $fn"
		return 1
	fi
	while [ -z "$eof" ]; do
		read -r str || eof=1
		case "$str" in
			"["*"]")
				# Reset section variable on section change
				sect=
				[ "$str" != "[$section]" ] ||
					sect=1
				;;
			"$shell_ini_config_comment"*|'')
				;;
			*)
				if [ -n "$sect" ]; then
					shell_var_trim n "${str%%=*}"
					if [ "$n" = "$var" ]; then
						shell_var_trim v "${str#*=}"
						printf '%s\n' "$v"
						break
					fi
				fi
				;;
		esac
	done < "$fn"
}
# Usage: ini_config_is_set file section var
ini_config_is_set()
{
	local fn section var sect='' str eof='' n v
	fn="$1" section="$2" var="$3"
	if [ ! -e "$fn" ]; then
		message "No such file or directory: $fn"
		return 1
	fi
	while [ -z "$eof" ]; do
		read -r str || eof=1
		case "$str" in
			"["*"]")
				# Reset section variable on section change
				sect=
				[ "$str" != "[$section]" ] ||
					sect=1
				;;
			"$shell_ini_config_comment"*|'')
				;;
			*)
				if [ -n "$sect" ]; then
					shell_var_trim n "${str%%=*}"
					if [ "$n" = "$var" ]; then
						# Return success, since we found match.
						return 0
					fi
				fi
				;;
		esac
	done < "$fn"
	# We did not find match, so return failure.
	return 1
}
ini_config_set()
{
	local fn fn_tmp section var value sect='' don='' str tstr eof='' n v
	fn="$1" section="$2" var="$3" value="$4"
	if [ ! -e "$fn" ]; then
		message "No such file or directory: $fn"
		return 1
	fi
	fn_tmp="$(mktemp "$fn.XXXXXX")"
	while [ -z "$eof" ]; do
		IFS='' read -r str || eof=1
		shell_var_trim tstr "$str"
		case "$tstr" in
			"[$section]")
				sect=2
				printf '%s\n' "$tstr"
				;;
			"["*"]")
				if [ "$sect" = 2 ] && [ -z "$don" ]; then
					__ini_config_print 1 "$var = $value"
					don=1
				fi
				sect=1
				printf '%s\n' "$tstr"
				;;
			"$shell_ini_config_comment"*|'')
				[ -n "$tstr" ] &&
					__ini_config_print '' "$str" ||
					{ [ -n "$eof" ] || printf '\n'; }
				;;
			*)
				if [ -z "$sect" ]; then
					printf '%s\n' "$str"
					continue
				fi
				shell_var_trim n "${tstr%%=*}"
				shell_var_trim v "${tstr#*=}"
				if [ "$sect" = 2 ] && [ "$n" = "$var" ]; then
					[ -n "$don" ] ||
						__ini_config_print 1 "$n = $value"
					don=1
					continue
				fi
				if [ -z "${tstr##*=*}" ]; then
					__ini_config_print 1 "$n = $v"
				else
					__ini_config_print 1 "$n"
				fi
				;;
		esac
		if [ -n "$eof" ] && [ -z "$don" ]; then
			[ "$sect" = 2 ] ||
				printf '[%s]\n' "$section"
			__ini_config_print 1 "$var = $value"
		fi
	done < "$fn" > "$fn_tmp"
	chmod --reference="$fn" "$fn_tmp"
	mv -f -- "$fn_tmp" "$fn"
}
__ini_config_del_comment()
{
	local fn_tmp sect='' str tstr eof='' n v
	fn_tmp="$(mktemp "$fn.XXXXXX")"
	while [ -z "$eof" ]; do
		IFS='' read -r str || eof=1
		shell_var_trim tstr "$str"
		case "$tstr" in
			"["*"]")
				sect=1
				[ "$tstr" != "[$section]" ] ||
					sect=2
				printf '%s\n' "$tstr"
				;;
			"$shell_ini_config_comment"*|'')
				[ -n "$tstr" ] &&
					__ini_config_print '' "$str" ||
					{ [ -n "$eof" ] || printf '\n'; }
				;;
			*)
				if [ -z "$sect" ]; then
					printf '%s\n' "$str"
					continue
				fi
				shell_var_trim n "${tstr%%=*}"
				shell_var_trim v "${tstr#*=}"
				if [ -z "${tstr##*=*}" ]; then
					if [ "$sect" = 2 ]; then
						__ini_config_action 2 "$n" "$v"
					else
						__ini_config_print 1 "$n = $v"
					fi
				else
					if [ "$sect" = 2 ]; then
						__ini_config_action 1 "$n"
					else
						__ini_config_print 1 "$n"
					fi
				fi
				;;
		esac
	done < "$fn" > "$fn_tmp"
	chmod --reference="$fn" "$fn_tmp"
	mv -f -- "$fn_tmp" "$fn"
	unset -f __ini_config_action
}
ini_config_del()
{
	local fn="$1" section="$2" var="${3-}"
	if [ ! -e "$fn" ]; then
		message "No such file or directory: $fn"
		return 1
	fi
	__ini_config_action()
	{
		if [ -n "$var" ] && [ ! "$2" = "$var" ]; then
			[ "$1" = 2 ] &&
				__ini_config_print 1 "$2 = $3" ||
				__ini_config_print 1 "$2"
		fi
	}
	__ini_config_del_comment
}
ini_config_comment()
{
	local fn="$1" section="$2" var="${3-}"
	if [ ! -e "$fn" ]; then
		message "No such file or directory: $fn"
		return 1
	fi
	__ini_config_action()
	{
		if [ -n "$var" ] && [ "$2" != "$var" ]; then
			[ "${1}" = 2 ] && __ini_config_print 1 "$2 = $3" ||
				__ini_config_print 1 "$2"
			return
		fi
		[ "$1" = 2 ] &&
			__ini_config_print 1 "$shell_ini_config_comment $2 = $3" ||
			__ini_config_print 1 "$shell_ini_config_comment $2"
	}
	__ini_config_del_comment
}

### shell-json
JSON_FOREACH_ABORT=100
JSON_DEBUG=
__json_debug()
{
	[ -z "$JSON_DEBUG" ] ||
		printf >&2 'json: %s\n' "$*"
}
__json_push_name()
{
	eval "__json_name_$__json_name=\"\$1\""
	__json_name=$(( $__json_name + 1 ))
}
__json_pop_name()
{
	__json_name=$(( $__json_name - 1 ))
	eval "unset __json_name_$__json_name"
}
json_get_last_name()
{
	eval "$1=\"\${__json_name_$(( $__json_name - 1 ))-}\""
}
json_get_full_name()
{
	local __i=0 __v=''
	while [ "$__i" -lt "$__json_name" ]; do
		eval "__v=\"\$__v${2-/}\${__json_name_$__i-}\""
		__i=$(( $__i + 1 ))
	done
	eval "$1=\"\$__v\""
}
__json_get_stack()
{
	local i=0
	stack=''
	while [ "$i" -lt "$__json_states" ]; do
		eval "stack=\"\${stack:+\$stack -> }\${__json_states_$i-}\""
		i=$(( $i + 1 ))
	done
	stack="${stack:-none}"
}
__json_push_state()
{
	if [ -n "${JSON_DEBUG-}" ]; then
		local stack
		__json_get_stack
		__json_debug "state: append: $stack -> { $1 }"
	fi
	__json_state="$1"
	eval "__json_states_$__json_states=\"\$1\""
	__json_states=$(( $__json_states + 1 ))
}
__json_pop_state()
{
	local prev="$__json_state"
	__json_states=$(( $__json_states - 1 ))
	eval "unset __json_states_$__json_states"
	eval "__json_state=\"\${__json_states_$(( $__json_states - 1 ))-}\""
	if [ -n "${JSON_DEBUG-}" ]; then
		local stack
		__json_get_stack
		__json_debug "state: remove: $stack // { $prev }"
	fi
}
json_foreach_handler()
{
	local name=''
	json_get_full_name name
	printf '%s %s %s\n' "${name:-/}" "$1" "$2"
}
__json_handle()
{
	if [ -n "$__json_handle" ]; then
		local IFS="$SAVE_IFS"
		json_foreach_handler "$1" "$2"
	fi
}
# Consume standard input one character at a time to parse JSON.
json_foreach()
{
	local __json_l __json_m __json_c __json_p __json_eof __json_buffer __json_state
	local __json_name=0 __json_states=0
	local __json_handle=1
	local SAVE_IFS="$IFS"
	local IFS='
'
	local __json_read_opt_n=
	# shellcheck disable=SC2169
	! { echo -n 1 | read -n1 -r; } 2>/dev/null ||
		__json_read_opt_n=1
	__json_buffer='' __json_eof='' __json_p=''
	# Set incoming state of json.
	__json_push_state 'value'
	while [ -z "$__json_eof" ]; do
		read ${__json_read_opt_n:+-n 9} -r __json_l || __json_eof=1
		fill_mask __json_m "$__json_l"
		while [ -n "$__json_l" ]; do
			__json_c="${__json_l%$__json_m}"
			__json_l="${__json_l#?}"
			__json_m="${__json_m#?}"
			[ -n "${__json_c##
}" ] ||
				continue
			__json_char || [ $? -ne $JSON_FOREACH_ABORT ] ||
				return 0
			__json_p="$__json_c"
		done
	done
	__json_c='
'
	__json_char ||:
	if [ "$__json_states" -gt 0 ]; then
		local stack
		__json_get_stack
		fatal "unfinished json: $stack"
	fi
}
__json_char()
{
	while :; do
		case "$__json_state" in
			'value')
				case "$__json_c" in
					'	'|' '|'')
						;;
					'[')
						__json_push_name 0
						__json_push_state 'array'
						;;
					'{')
						__json_push_state 'object'
						;;
					'"')
						__json_push_state 'string'
						__json_buffer=
						;;
					0)
						__json_push_state 'number-leading-zero'
						__json_buffer="$__json_c"
						;;
					[1-9])
						__json_push_state 'number-leading-nonzero'
						__json_buffer="$__json_c"
						;;
					'-')
						__json_push_state 'number-negative'
						__json_buffer="$__json_c"
						;;
					't'|'f')
						__json_push_state 'boolean'
						__json_buffer=
						continue
						;;
					'n')
						__json_push_state 'null'
						__json_buffer=
						continue
						;;
					'
')
						__json_pop_state 'value'
						;;
					*)
						__json_pop_state 'value'
						continue
						;;
				esac
				;;
			'array')
				case "$__json_c" in
					'	'|' '|'')
						;;
					']')
						__json_pop_name
						__json_pop_state 'array'
						;;
					*)
						__json_push_state 'array-more'
						__json_push_state 'value'
						continue
						;;
				esac
				;;
			'array-more')
				case "$__json_c" in
					'	'|' '|'')
						;;
					']')
						__json_pop_name
						__json_pop_state 'object-more'
						__json_pop_state 'array'
						;;
					',')
						local last
						json_get_last_name last
						__json_pop_name
						__json_push_name $(( $last + 1 ))
						__json_push_state 'value'
						;;
					'"')
						continue
						;;
					*)
						fatal "$__json_state unexpected '$__json_c'"
						;;
				esac
				;;
			'object')
				case "$__json_c" in
					'	'|' '|'')
						;;
					'"')
						__json_handle=
						__json_push_state 'object-more'
						__json_push_state 'object-name'
						__json_push_state 'value'
						continue
						;;
					'}')
						__json_pop_state 'object'
						;;
					*)
						fatal "$__json_state unexpected '$__json_c'"
						;;
				esac
				;;
			'object-name')
				case "$__json_c" in
					'	'|' '|'')
						;;
					'"')
						__json_push_state 'value'
						continue
						;;
					':')
						__json_handle=1
						__json_push_name "$__json_buffer"
						#echo "object-name $__json_buffer"
						__json_pop_state 'object-name'
						__json_push_state 'value'
						;;
					*)
						fatal "$__json_state unexpected '$__json_c'"
						;;
				esac
				;;
			'object-more')
				case "$__json_c" in
					'	'|' '|'')
						;;
					'}')
						__json_pop_name
						__json_pop_state 'object-more'
						__json_pop_state 'object'
						;;
					',')
						__json_pop_name
						__json_handle=
						__json_push_state 'object-name'
						;;
					'"')
						__json_handle=
						__json_push_state 'object-name'
						continue
						;;
					*)
						fatal "$__json_state unexpected '$__json_c'"
						;;
				esac
				;;
			'boolean')
				# Boolean values are multicharacter literals but they're unique
				# from their first character.  This means the eventual value is
				# already known when the "boolean" state is entered so we can
				# raise syntax errors as soon as the input goes south.
				case "$__json_buffer$__json_c" in
					't'|'tr'|'tru'|'f'|'fa'|'fal'|'fals')
						__json_buffer="$__json_buffer$__json_c"
						;;
					'true'|'false')
						__json_pop_state 'boolean'
						__json_handle boolean "$__json_buffer$__json_c" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						;;
					*)
						fatal "$__json_state unexpected '$__json_c'"
						;;
				esac
				;;
			'null')
				# Null values work exactly like boolean values.  See above.
				case "$__json_buffer$__json_c" in
					'n'|'nu'|'nul')
						__json_buffer="$__json_buffer$__json_c"
						;;
					'null')
						__json_pop_state 'null'
						__json_handle null "$__json_buffer$__json_c" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						;;
					*)
						fatal "$__json_state unexpected '$__json_c'"
						;;
				esac
				;;
			'string')
				# shellcheck disable=SC1003
				case "$__json_p$__json_c" in
					'\"'|'\/'|'\\')
						__json_buffer="$__json_buffer$__json_c"
						;;
					'\b'|'\f'|'\n'|'\r'|'\t'|'\u')
						__json_buffer="$__json_buffer\\$__json_c"
						;;
					*'"')
						__json_pop_state 'string'
						__json_handle string "$__json_buffer" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						;;
					*'\')
						;;
					*)
						__json_buffer="$__json_buffer$__json_c"
						;;
				esac
				;;
			'number-negative')
				# This is an entrypoint into parsing a number, used when
				# the first character consumed is a '-'.  From here, a number
				# may progress to the "number-leading-nonzero" or
				# "number-leading-zero" states.
				__json_pop_state 'number-negative'
				case "$__json_c" in
					'0')
						__json_push_state 'number-leading-zero'
						__json_buffer="$__json_buffer$__json_c"
						;;
					[1-9])
						__json_push_state 'number-leading-nonzero'
						__json_buffer="$__json_buffer$__json_c"
						;;
					*)
						__json_handle number "$__json_buffer" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						__json_buffer=
						continue
						;;
				esac
				;;
			'number-leading-zero')
				# This is an entrypoint into parsing a number, used when
				# the first digit consumed is zero.  From here, a number
				# may remain zero, become a floating-point number by
				# consuming a '.', or become scientific-notation by consuming
				# an 'E' or 'e'.
				__json_pop_state 'number-leading-zero'
				case "$__json_c" in
					'.')
						__json_push_state 'number-float'
						__json_buffer="$__json_buffer$__json_c"
						;;
					[eE])
						__json_push_state 'number-sci'
						__json_buffer="$__json_buffer$__json_c"
						;;
					[0-9])
						fatal "$__json_state unexpected '$__json_buffer$__json_c'"
						;;
					*)
						__json_handle number "$__json_buffer" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						__json_buffer=
						continue
						;;
				esac
				;;
			'number-leading-nonzero')
				# This is an entrypoint into parsing a number, used when
				# the first digit consumed is non-zero.  From here, a number
				# may continue on a positive integer, become a floating-point
				# number by consuming a '.', or become scientific-notation by
				# consuming an 'E' or 'e'.
				case "$__json_c" in
					'.')
						__json_pop_state 'number-leading-nonzero'
						__json_push_state 'number-float'
						__json_buffer="$__json_buffer$__json_c"
						;;
					[eE])
						__json_pop_state 'number-leading-nonzero'
						__json_push_state 'number-sci'
						__json_buffer="$__json_buffer$__json_c"
						;;
					[0-9])
						__json_buffer="$__json_buffer$__json_c"
						;;
					*)
						__json_pop_state 'number-leading-nonzero'
						__json_handle number "$__json_buffer" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						__json_buffer=
						continue
						;;
				esac
				;;
			'number-float')
				# Numbers that encounter a '.' become floating point and may
				# continue consuming digits forever or may become
				# scientific-notation.
				case "$__json_c" in
					[eE])
						__json_pop_state 'number-float'
						__json_push_state 'number-sci'
						__json_buffer="$__json_buffer$__json_c"
						;;
					[0-9])
						__json_buffer="$__json_buffer$__json_c"
						;;
					*)
						__json_pop_state 'number-float'
						__json_handle number "$__json_buffer" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						__json_buffer=
						continue
						;;
				esac
				;;
			'number-sci')
				# Numbers that encounter an 'E' or 'e' become
				# scientific-notation and consume digits, optionally prefixed
				# by a '+' or '-', forever.  The actual consumption is
				# delegated to the "number-sci-neg" and "number-sci-pos"
				# states.  Any other character immediately following the 'E'
				# or 'e' is a syntax error.
				__json_pop_state 'number-sci'
				case "$__json_c" in
					[0-9]|'+'|'-')
						__json_push_state 'number-sci-digits'
						__json_buffer="$__json_buffer$__json_c"
						;;
					*)
						fatal "$__json_state unexpected '$__json_buffer$__json_c'"
						;;
				esac
				;;
			'number-sci-digits')
				# Once in these states, numbers may consume digits forever.
				case "$__json_c" in
					[0-9])
						__json_buffer="$__json_buffer$__json_c"
						;;
					*)
						__json_pop_state 'number-sci-digits'
						__json_handle number "$__json_buffer" || [ $? -ne $JSON_FOREACH_ABORT ] ||
							return $JSON_FOREACH_ABORT
						__json_buffer=
						continue
						;;
				esac
				;;
		esac
		__json_debug "c='$__json_c'"
		break
	done
}
# vim: tw=200

### shell-quote
quote_sed_regexp_variable()
{
	local __quote_set_regexp_variable_var __quote_set_regexp_variable_out
	__quote_set_regexp_variable_var="$1"; shift
	__quote_set_regexp_variable_out="$*"
	if [ -z "${__quote_set_regexp_variable_out##*[\[\].*&^\$\\\\/]*}" ]; then
		__quote_set_regexp_variable_out="$(printf %s "$__quote_set_regexp_variable_out" |
				sed -e 's/[].*&^$[\/]/\\&/g')" ||
			return 1
	fi
	eval "$__quote_set_regexp_variable_var=\"\$__quote_set_regexp_variable_out\""
}
quote_sed_regexp()
{
	local result
	quote_sed_regexp_variable result "$@"
	printf %s "$result"
}
quote_shell_variable()
{
	local __quote_shell_variable_var __quote_shell_variable_out
	__quote_shell_variable_var="$1"; shift
	__quote_shell_variable_out="$*"
	if [ -z "${__quote_shell_variable_out##*[\"\$\`\\\\]*}" ]; then
		__quote_shell_variable_out="$(printf %s "$__quote_shell_variable_out" |
				sed -e 's/[\"$\`\\]/\\&/g')" ||
			return 1
	fi
	eval "$__quote_shell_variable_var=\"\$__quote_shell_variable_out\""
}
quote_shell()
{
	local result
	quote_shell_variable result "$@"
	printf %s "$result"
}
quote_shell_args()
{
__quote_shell_args() {
	local m='' r='' c='' l="$1"
	local bq='' dq='' sq=''
	__quote_shell_args_toggle() {
		eval [ -n \"\$$1\" ] && eval "$1=" || eval "$1=\$$2"
	}
	fill_mask m "$l"
	while [ -n "$l" ]; do
		c="${l%$m}"
		l="${l#?}"
		m="${m#?}"
		case "$c" in
			\")
				[ -n "$bq$sq" ] || __quote_shell_args_toggle dq c
				;;
			\')
				[ -n "$bq$dq" ] || __quote_shell_args_toggle sq c
				;;
			\$|\`)
				[ -n "$bq$sq" ] || bq=\\
				;;
			\\)
				if [ -z "$sq" ]; then
					if [ -z "$bq" ]; then
						bq=\\
						continue
					else
						r="$r\\"
						bq=
					fi
				fi
				;;
			[!A-Za-z0-9_\ \	])
				[ -n "$bq$dq$sq" ] || bq=\\
				;;
		esac
		r="$r$bq$c"
		bq=
	done
	[ -z "$bq$dq$sq" ] ||
		{ message "unmatched character ($bq$dq$sq) found"; return 1; }
	__quote_shell_args_out="$r"
}
	local __quote_shell_args_out='' __quote_shell_args_rc=0
	__quote_shell_args "$2" ||
		__quote_shell_args_rc=1
	eval "$1=\"\$__quote_shell_args_out\""
	unset -f __quote_shell_args __quote_shell_args_toggle
	return $__quote_shell_args_rc
}
if [ -n "${__export_compatibility_string_quote_remove-}" ]; then
string_quote_remove()
{
	local out="$1"
	if [ -z "${1##*\'}${1%%\'*}" ]; then
		out="${1#\'}"
		out="${out%\'}"
	elif [ -z "${1##*\"}${1%%\"*}" ]; then
		out="${1#\"}"
		out="${out%\"}"
	fi
	printf %s "$out"
}
fi # __export_compatibility_string_quote_remove

### shell-run
run_if_executable()
{
	local v f
	f="$1"; shift
	! __shell_source_find v "$f" || [ ! -x "$v" ] || "$v" ${1:+"$@"}
}
RUN_SCRIPTS_EXCLUDE='*.rpm* *.swp *,v *~ *.#'
SCRIPT_ERROR_FATAL=${SCRIPT_ERROR_FATAL:-false}
run_scripts()
{
	[ "$#" -ge 1 ] ||
		fatal "Usage: run_scripts <dir> [args]"
	local p f d rc=0
	d="$(opt_check_dir "dir" "$1")"; shift
	for f in $(find -L "$d" -mindepth 1 -maxdepth 1 -type f | sort); do
		for p in $RUN_SCRIPTS_EXCLUDE; do
			[ -n "${f##$p}" ] ||
				continue 2
		done
		run_if_executable "$f" ${1:+"$@"} || rc=1
		[ "$SCRIPT_ERROR_FATAL" = true ] &&
			[ $rc -gt 0 ] && return $rc
	done
	return $rc
}

### shell-signal
__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
}
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
}
__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
}
unset_cleanup_handler()
{
	signal_handler SIG_DFL EXIT HUP PIPE INT QUIT TERM
	__cleanup_handler_name=
}

### shell-temp
__shell_clean_temp=0
__shell_clean_temp()
{
	local i=0 temp=
	while [ $i -lt ${__shell_clean_temp:-0} ]; do
		eval "temp=\"\$__shell_clean_temp_$i\""
		rm $verbose -rf -- "$temp"
		i=$(($i + 1))
	done
}
create_temporary()
{
	local __create_temporary_out __create_temporary_var="$1"
	shift
	[ "$#" != 0 ] || set -- -dt
	__create_temporary_out="$(mktemp "$@" "$PROG.XXXXXXXXX")"
	eval "__shell_clean_temp_$__shell_clean_temp=\"\$__create_temporary_out\""
	[ "$__shell_clean_temp" != 0 ] ||
		signal_handler __shell_clean_temp EXIT HUP PIPE INT QUIT TERM
	__shell_clean_temp=$(($__shell_clean_temp + 1))
	eval "$__create_temporary_var=\"\$__create_temporary_out\""
}

### shell-config
__shell_config_comment='#'
shell_config_get()
{
	[ "$#" -ge 2 ] && [ "$#" -le 3 ] ||
		fatal "Usage: shell_config_get file name [delim]"
	local file="$1" name="$2" delim="${3-=}"
	[ -s "$file" ] ||
		return 0
	quote_sed_regexp_variable name "$name"
	sed -n -e "s/^[[:space:]]*$name$delim//p" -- "$file"
}
shell_config_set()
{
	[ "$#" -ge 3 ] && [ "$#" -le 5 ] ||
		fatal "Usage: shell_config_set file name value [read-delim [write-delim]]"
	local file="$1" name="$2" value="$3" r_delim="${4-=}" w_delim="${5-=}"
	local n v nv='' created=''
	if [ ! -f "$file" ]; then
		if [ ! -w "${file%/*}" ]; then
			message "${file%/*}: not writable."
			return 1
		fi
		touch -- "$file" ||
			return 1
		created=1
	fi
	if [ -z "$created" ]; then
		quote_sed_regexp_variable n "$name"
		if v="$(grep -m1 "^[[:space:]]*$n$r_delim" -- "$file" 2>/dev/null)"; then
			if [ "${v#*$name$r_delim}" != "$value" ]; then
				quote_sed_regexp_variable nv "$w_delim$value"
				sed -i -e "s/^[[:space:]]*$n$r_delim.*/$n$nv/" -- "$file"
			fi
			return
		fi
		if [ -n "${__shell_config_comment-}" ] &&
		   v="$(grep -m1 "^[[:space:]]*${__shell_config_comment:-#}[[:space:]]*$n$r_delim" -- "$file" 2>/dev/null)"; then
			quote_sed_regexp_variable v "$v"
			quote_sed_regexp_variable nv "$w_delim$value"
			sed -i -e "s/^$v\$/$n$nv/" -- "$file"
			return
		fi
	fi
	printf '%s\n' "$name$w_delim$value" >> "$file"
}
shell_config_del()
{
	[ "$#" -ge 2 ] && [ "$#" -le 3 ] ||
		fatal "Usage: shell_config_del file name [delim]"
	local file="$1" name="$2" delim="${3-=}"
	[ -s "$file" ] ||
		return 0
	quote_sed_regexp_variable name "$name"
	sed -i -e "/^[[:space:]]*$name$delim/d" -- "$file"
}
shell_config_comment()
{
	[ "$#" -ge 2 ] && [ "$#" -le 3 ] ||
		fatal "Usage: shell_config_comment file name [delim]"
	local file="$1" name="$2" delim="${3-=}"
	[ -s "$file" ] ||
		return 0
	quote_sed_regexp_variable name "$name"
	sed -i -e "s/^[[:space:]]*$name$delim.*/${__shell_config_comment:-#}&/" -- "$file"
}

### shell-getopt
GETOPT_ALLOW_UNKNOWN=
GETOPT_ALLOW_ABBREV=1
GETOPT_ALLOW_ALTERNATIVE=
OPTERR=1
OPTTYP=
OPTUKN=
OPTOPT=
OPTARG=
OPTIND=1
OPTOFS=
getoptex()
{
	[ "$#" -gt 0 ] ||
		return 1
	[ "${OPTIND-}" -gt 0 ] 2>/dev/null ||
		OPTIND=1
	[ "$OPTIND" -lt "$#" ] ||
		return 1
	getoptex_badarg()
	{
		[ -z "${OPTERR-}" ] ||
			message "option requires an argument -- '$OPTOPT'"
		OPTARG="$OPTOPT"
		OPTOPT='?'
	}
	getoptex_argument()
	{
		[ "$OPTTYP" = ':' ] ||
			return 0
		OPTARG="$1"
		[ -n "$OPTARG" ] && [ -n "${OPTARG%%-*}" ] ||
			{ getoptex_badarg; return 1; }
		OPTARG="${1#[#]}"
		OPTIND=$(($OPTIND+1))
	}
	getoptex_option_long()
	{
		local p
		for p in -- ${GETOPT_ALLOW_ALTERNATIVE:+-}; do
			p="$p$OPTOPT"
			case "$1" in
				$p=*)
					[ -n "$OPTTYP" ] ||
						{ getoptex_badarg; return 3; }
					OPTARG="${1#$p=}"
					return 1
					;;
				"$p")
					getoptex_argument "$2" ||
						return 3
					return 1
					;;
			esac
		done
	}
	getoptex_option_short()
	{
		local o="-${1#-${OPTOFS-}}"
		case "$o" in
			"-$OPTOPT")
				OPTOFS=
				getoptex_argument "$2" ||
					return 3
				return 1
				;;
			-$OPTOPT*)
				if [ -z "$OPTTYP" ]; then
					OPTOFS="${OPTOFS-}?"
					OPTIND=$(($OPTIND-1))
				else
					OPTOFS=
					OPTARG="${o#-$OPTOPT}"
				fi
				return 1
				;;
		esac
	}
	getoptex_option_abbrev()
	{
		[ "$1" != '--' ] ||
			return 0
		local opt o i=0 variants='' l='' v='' n="${1%%=*}"
		[ -n "${1##*=*}" ] || v="${1#*=}"
		shift
		for opt; do
			opt="${opt%[;.:]}"
			[ "${#opt}" -gt 1 ] ||
				continue
			for o in -- ${GETOPT_ALLOW_ALTERNATIVE:+-}; do
				o="$o$opt"
				[ -z "${o##$n*}" ] ||
					continue
				l="--$opt"
				if [ "$o" = "$n" ]; then
					# Full match was found, so all other variants should be ignored.
					variants=
					i=1
					break 2
				else
					#local d='--'
					#[ -z "${GETOPT_ALLOW_ALTERNATIVE-}" ] || d='-'
					#variants="$variants '$d$opt'"
					variants="$variants '--$opt'"
					i=$(($i+1))
				fi
			done
		done
		if [ "$i" -eq 1 ]; then
			param="$l${v:+=$v}"
		elif [ "$i" -gt 1 ]; then
			message "option '$n${v:+=$v}' is ambiguous; possibilities:$variants"
			return 1
		fi
	}
	local optlist="${1#;}" param='' value=''
	shift $OPTIND
	param="$1"
	if [ -n "${GETOPT_ALLOW_ABBREV-}" ]; then
		if ! getoptex_option_abbrev "$param" $optlist && [ -z "${GETOPT_ALLOW_UNKNOWN-}" ]; then
			OPTIND=$(($OPTIND+1))
			OPTOPT='?'
			OPTARG=
			return 2
		fi
	fi
	[ "$#" -lt 2 ] ||
		value="#$2"
	OPTTYP=
	if [ "$param" = '--' ]; then
		OPTTYP='--'
		OPTIND=$(($OPTIND+1))
	elif [ "$param" != '-' ] && [ "$param" != "${param#-}" ]; then
		OPTIND=$(($OPTIND+1))
		local cmd argtype
		for opt in $optlist; do
			OPTOPT="${opt%[;.:]}"
			OPTARG=
			OPTTYP=
			[ "$OPTTYP" = ';' ] ||
				OPTTYP="${opt#$OPTOPT}"
			cmd=long
			[ "${#OPTOPT}" -gt 1 ] ||
				cmd=short
			getoptex_option_$cmd "$param" "$value" ||
				return $(($?-1))
		done
		OPTOPT='?'
		OPTARG=
		if [ -n "${GETOPT_ALLOW_UNKNOWN-}" ]; then
			local q_arg
			quote_shell_variable q_arg "$param"
			OPTUKN="${OPTUKN-} \"$q_arg\""
			return 0
		fi
		message "unrecognized option '$param'"
		return 2
	fi
	OPTOPT='?'
	OPTARG=
	return 1
}
getopts()
{
	local l="$1"
	local m=
	local r=
	fill_mask m "$l"
	while [ -n "$l" ]; do
		r="${r:+"$r "}${l%$m}"
		l="${l#?}"
		m="${m#?}"
		if [ "${l#[:.;]}" != "$l" ]; then
			r="$r${l%$m}"
			l="${l#?}"
			m="${m#?}"
		fi
	done
	shift
	getoptex "$r" ${1:+"$@"} ||
		return $?
}
__getsubopt_arguments=
getsubopt()
{
	local l="$2"
	if [ -z "$__getsubopt_arguments" ]; then
		local ch m=
		fill_mask m "$l"
		__getsubopt_arguments='--'
		while [ -n "$l" ]; do
			ch="${l%$m}"
			l="${l#?}"
			m="${m#?}"
			# shellcheck disable=SC2102
			# Disable this `Ranges can only match single chars (mentioned due to duplicates)`
			# because some shells treat escaped characters differently.
			case "$ch" in
				,) ch=' --' ;;
				[\\\\\`\$\"\ ]) ch="\\$ch" ;;
			esac
			__getsubopt_arguments="$__getsubopt_arguments$ch"
		done
	fi
	local GETOPT_ALLOW_ABBREV=
	eval getoptex "\"$1\"" "$__getsubopt_arguments" ||
		return $?
}
GETOPT_POSIXLY_CORRECT=
getopt()
{
	__getopt_version()
	{
		cat <<-EOF
		$PROG version $libshell_version
		Written by Alexey Gladkov <gladkov.alexey@gmail.com>
		Copyright (C) 2008  Alexey Gladkov <gladkov.alexey@gmail.com>
		This is free software; see the source for copying conditions.  There is NO
		warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
		EOF
	}
	__getopt_usage()
	{
		cat <<-EOF
		Try \`$PROG --help' for more information.
		EOF
	}
	__getopt_help()
	{
		cat <<-EOF
		Usage: $PROG optstring parameters
		   or: $PROG [options] [--] optstring parameters
		   or: $PROG [options] -o|--options optstring [options] [--] parameters
		Options ignored:
		  -s, --shell=shell            Set shell quoting conventions;
		  -u, --unqote                 Do not quote the output;
		Options:
		  -a, --alternative            Allow long options starting with single -;
		  -l, --longoptions=longopts   Long options to be recognized;
		  -n, --name=progname          The name under which errors are reported;
		  -o, --options=optstring      Short options to be recognized;
		  -q, --quiet                  Disable error reporting;
		  -Q, --quiet-output           No normal output;
		  -T, --test                   Test for getopt version;
		  -V, --version                Output version information;
		  -h, --help                   This small usage guide.
		Report bugs to http://bugzilla.altlinux.org/
		EOF
	}
	local PROG='getopt' OPTIND=1 OPTERR=1 prg='' opts='' lopts='' quiet_output='' alt='' order='' rc
	local GETOPT_POSIXLY_CORRECT
	while getoptex 'a alternative h help l: longoptions: n: name: o: options: q quiet Q quiet-output s shell T test u unquoted V version' ${1:+"$@"} && rc=0 || rc=$?; do
		case "$rc" in
			2) __getopt_usage; return 2 ;;
			1) break ;;
		esac
		case "$OPTOPT" in
			a|alternative) alt=1 ;;
			n|name) prg="$OPTARG" ;;
			o|options) opts="$OPTARG " ;;
			l|longoptions) lopts="$OPTARG" ;;
			q|quiet) OPTERR= ;;
			Q|quiet-output) quiet_output=1 ;;
			T|test) return 4 ;;
			V|version)
				__getopt_version
				return 0
				;;
			h|help)
				__getopt_help
				return 2
				;;
		esac
	done
	shift $(($OPTIND-1))
	set -- ${1:+"$@"}
	if [ -z "${opts##+*}" ]; then
		opts="${opts#+}"
		GETOPT_POSIXLY_CORRECT=1
	elif [ -z "${opts##-*}" ]; then
		opts="${opts#-}"
		order=1
	fi
	if [ -z "$opts" ]; then
		if [ "$#" -gt 1 ] && [ "${1#-}" = "$1" ] && [ "$1" != '--' ]; then
			opts="$1"
			shift
		else
			message "$PROG: missing optstring argument"
			__getopt_usage
			return 2
		fi
	fi
	opts="${lopts:+$lopts,}$opts"
	while :; do
		case "$opts" in
			*,*)  opts="${opts%%,*} ${opts#*,}"   ;;
			*::*) opts="${opts%%::*}.${opts#*::}" ;;
			*) break ;;
		esac
	done
	local OPTIND=1 OPTOFS='' GETOPT_ALLOW_ALTERNATIVE="${alt:+1}"
	local ret=0 out=' -- '
	! printenv POSIXLY_CORRECT >/dev/null 2>&1 ||
		GETOPT_POSIXLY_CORRECT=1
	__getopt_out_arg()
	{
		local q_arg
		shift $(($OPTIND-1))
		quote_shell_variable q_arg "$1"
		[ -z "$order" ] &&
			out="${out%% -- *} -- ${out#* -- } \"$q_arg\"" ||
			out="${out%% -- *} \"$q_arg\" -- ${out#* -- }"
	}
	PROG="$prg"
	while getoptex "$opts" ${1:+"$@"} && rc=0 || rc=$?; do
		case "$rc" in
			1)
				[ $# -ge $OPTIND ] && [ -z "${GETOPT_POSIXLY_CORRECT-}" ] ||
					break
				__getopt_out_arg ${1:+"$@"}
				OPTIND=$(($OPTIND+1))
				[ "$OPTTYP" != '--' ] ||
					break
				continue
				;;
			2)	ret=1
				;;
		esac
		if [ "$OPTOPT" = '?' ]; then
			if [ -n "$GETOPT_ALLOW_UNKNOWN" ]; then
				out="${out%% -- *} -- ${out#* -- }$OPTUKN"
				OPTUKN=
			fi
			continue
		fi
		pfx='-'
		[ "${#OPTOPT}" -eq 1 ] ||
			pfx='--'
		# shellcheck disable=SC2027
		# Disable `The surrounding quotes actually unquote this`
		# because $OPTARG actually quoted.
		out="${out%% -- *} $pfx$OPTOPT${OPTTYP:+ "'"$OPTARG"'"} -- ${out#* -- }"
	done
	local q_arg
	shift $(($OPTIND-1))
	set -- ${1:+"$@"}
	while [ "$#" -gt 0 ]; do
		quote_shell_variable q_arg "$1"
		out="${out%% -- *} -- ${out#* -- } \"$q_arg\""
		shift
	done
	[ -n "$quiet_output" ] ||
		printf '%s\n' "$out${OPTUKN:+$OPTUKN}"
	return $ret
}
fi # __included_shell_single
