#!/bin/bash
#  settings - setting variable support

set -e


######
# Settings

core_settings_config_init() {
	lib_setting_vars settings_dump

	lib_setting_arrays -ro settings_types
	settings_types=( vars arrays assocs funcs )

	core_settings_config_check
}

core_settings_config_check() {
	settings_dump=${settings_dump:-$config_debug}
}


######
# Functions

settings_varname() { echo "${1}_settings_${2}"; }

settings_insert() {
	min_args 3 "$@"
	local ext=$1
	local name=$2
	shift 2

	# add them to the script settings array
	local settings
	settings=$(settings_varname "$name" "$ext")

	declare -ga $settings
	eval "${settings}=( \"\${${settings}[@]}\" \"\$@\" )"
}

settings_add() {
	min_args 4 "$@"
	local ext=$1
	local opts=$2
	local name=$3
	shift 3

	local ro=false
	local null=false
	local got_opt=true
	while $got_opt; do
		case "$1" in
		(-ro|--readonly) ro=true; shift; continue ;;
		(--empty|--null) null=true; shift; continue ;;
		(-*) error "$1: unknown option" ;;
		esac
		got_opt=false
	done

	settings_insert "all" "$name" "$@"
	! $null || settings_insert "null" "$name" "$@"
	! $ro || settings_insert "readonly" "$name" "$@"
	settings_insert "$ext" "$name" "$@"

	# declare all of the nammed settings as globals
	eval "declare -g $opts \"\$@\""
}

settings_add_vars() { settings_add "vars" "" "$@"; }
settings_add_funcs() { settings_add "funcs" "-f" "$@"; }
settings_add_assocs() { settings_add "assocs" "-A" "$@"; }
settings_add_arrays() { settings_add "arrays" "-a" "$@"; }


settings_list() {
	has_args 2 "$@"
	local settings
	settings=$(settings_varname "$1" "$2")
	eval "echo \${${settings}[@]}"
}

settings_list_all() { settings_list "$1" "all"; }
settings_list_vars() { settings_list "$1" "vars"; }
settings_list_funcs() { settings_list "$1" "funcs"; }
settings_list_assocs() { settings_list "$1" "assocs"; }
settings_list_arrays() { settings_list "$1" "arrays"; }
settings_list_readonly() { settings_list "$1" "readonly"; }
settings_list_null() { settings_list "$1" "null"; }

# settings_list_all2 - deprecated, but useful for testing
settings_list_all2() {
	echo $(for_each "settings_list $1" "${settings_types[@]}")
}

# settings_list_has_attr() - Checks if a given library setting exists
# in the named attribute list
#   $1 - setting name
#   $2 - library name
#   $3 - attribute to check
settings_list_has_attr() { in_list "$1" $(settings_list "$2" "$3"); }

is_setting_readonly() {
	has_args 2 "$@"
	settings_list_has_attr "$1" "$2" "readonly"
}

is_setting_nullable() {
	has_args 2 "$@"
	settings_list_has_attr "$1" "$2" "null"
}

######
# Setting Attribute Display

# settings_dump() - Dumps configuration settings for debugging
settings_dump() {
	$debug || return 0
	debug "Active Configuration:"
	for_each_lib_loaded settings_dump_lib
	settings_dump_tool
}

settings_dump_lib() { settings_dump_script "$(lib_symbol "$1")"; }
settings_dump_tool() { settings_dump_script "$(script_symbol "$1")"; }

settings_dump_script() {
	local name=$1

	if [ -z "$(settings_list_all "$name")" ]; then
		return
	fi

	local s
	debug "$name settings:"
	for s in $(settings_list_vars "$name"); do
		local v
		eval "v=\"\$$s\""

		local ro=" (ro)"
		is_setting_readonly "$s" "$name" || ro=""
		null=" (null)"
		is_setting_nullable "$s" "$name" || null=""

		local attr="$ro$null"
		debug "\t$s='$v'$attr"
	done
	for s in $(settings_list_arrays "$name"); do
		local v
		eval "v=\"( \${$s[*]} )\""
		debug "\t$s=$v"
	done
	for s in $(settings_list_assocs "$name"); do
		debug "\t$s=("

		local -a sk
		eval "sk=( \"\${!${s}[@]}\" )"

		local k
		for k in "${sk[@]}"; do
			local v
			eval "v=\${$s[\$k]}"
			debug "\t\t$k=$v"
		done

		debug "\t\t)"
	done
}


######
# Setting Attribute Verification

settings_check() {
	! $settings_dump || settings_dump

	info "checking configuration settings..."
	local -a settings_check_failures=()
	for_each_lib_loaded settings_check_lib
	settings_check_tool

	local failures="${settings_check_failures[*]}"
	[ "$failures" ] || return 0
	error "some scripts have configuration errors:\n\t$failures"
}

settings_check_lib() { settings_check_script "$1" "$(lib_symbol "$1")"; }
settings_check_tool() { settings_check_script "$1" "$(script_symbol "$1")"; }

settings_check_script() {
	local name=$1
	local sym=$2

	if [ -z "$(settings_list_all "$2")" ]; then
		return
	fi

	local -a vars
	vars=( $(settings_list_vars "$2") )
	list_filter settings_check_invalid vars

	[ "${vars[*]}" ] || return 0

	for_each settings_check_report "${vars[@]}"
	settings_check_failures+=( "$name" )
}

settings_check_invalid() {
	local var=$1
	local -n value=$var
	is_setting_nullable "$var" "$name" && [ -z "$value" ]
}

settings_check_report() { warn "\$$1 is not set"; }


######
# Settings Attribute Finalization

settings_final() {
	for_each_lib_loaded settings_final_lib
}

settings_final_lib() {
	local lib=$1
	local ext
	for ext in "${settings_types[@]}"; do
		local -a names
		names=( $(settings_list "$lib" "$ext") )

		list_filter "is_setting_readonly $lib" names
		[ "${names[*]}" ] || continue

		info "$lib: $ext: readonly: ${names[*]}"
		case "$ext" in
		(vars) typeset -gr "${names[@]}" ;;
		(arrays) typeset -gar "${names[@]}" ;;
		(assocs) typeset -gAr "${names[@]}" ;;
		(*) warn "$lib: $ext: readonly: ignoring ${names[*]}" ;;
		esac
	done
}

View the Script Reference Index


Generated on Tue Apr 25 21:20:17 PDT 2017 by mcsh i7 v0.18.0.