#!/bin/bash
# core/output - Bash Script Output Support

set -e


#;;;;;
#; Output Settings

timestamps=${timestamps:-true}
nanoseconds=${nanoseconds}
app_log_hook=app_log_stub
error_usage_hook=error_usage_stub


######
# Output Configuration

core_output_config_init() {
	# $timestamps - If set to ``true``, prefixes `stderr` with a timestamp.
	# Default: ``true``
	lib_setting_vars timestamps
	# $nanoseconds - If non-empty, timestamps will include nanoseconds.
	# Default: `null`
	lib_setting_vars --null nanoseconds
	# $app_log_hook - Name of function that implements ``app_log_pipe``.
	# Default: ``app_log_stub``
	lib_setting_vars app_log_hook
	# $error_usage_hook - Name of function that implements ``error_usage``.
	# Default: ``error_usage_stub``
	lib_setting_vars error_usage_hook
}


######
# Logging Hook

# app_log - Calls app_log_hook
app_log() { $app_log_hook "$@"; }

# script_log_pipe_stub - This definition is a temporary handler for debugging
#   library loading.  When the script library is loaded, it is replaced
#   by the final version located therein.
app_log_stub() { cat; }


######
# Timestamps

# timestamp() - Prints a timestamp if ``$timestamps`` is `true`.  If
# ``$nanoseconds`` is non-empty, the timestap will include nanoseconds.
timestamp() { ! $timestamps || date +"[%H:%M:%S${nanoseconds:+.%N}]"; }


######
# Basic Output

# _app_echo() - If logging is enabled, pipes the arguments ($@) to the
# logging function (``app_log()``); otherwise, this simply echos them.
_app_echo() { if $logging; then echo "$@" | app_log; else echo "$@"; fi; }

# app_echo() - Prints the arguments ($@), prefixed with ``timestamp()``.
app_echo() { _app_echo -e $(timestamp) "$*"; }

# app_echo_n() - Same as ``app_echo()`` but suppresses the trailing newline.
app_echo_n() { _app_echo -en $(timestamp) "$*"; }


######
# Namespace Output

# app_msg() - Prints arguments ($@) with ``app_echo()``, prefixed with the
# current command namespace.
app_msg() { app_echo "${script[*]} $*"; }

# app_msg_if() - Prints a message with ``app_msg()``
app_msg_if() {
	local x=$1
	shift
	if $x; then
		app_msg "$@" >&2
	else
		app_msg "$@" >/dev/null
	fi
}


######
# Information, Warnings, and Errors

# error() - Prints an error message ($*) to `stderr` and (conditionally)
# displays a stack trace.
# Returns: Always returns `false`.
error() { app_msg_if true "ERROR: $*"; stack_trace; false; }

# warn() - Prints a warning message ($*) to `stderr` unless ``$quiet``
# is true.
warn() { app_msg_if $(func_bool_not $quiet) "WARN: $*"; }

# info() - Prints an information message ($*) to `stderr` if
# ``$verbose`` is true.
info() { app_msg_if $verbose "INFO: $*"; }

# debug() - Prints an debugging message ($*) to `stderr` if
# ``$verbose`` is true.
debug() { app_msg_if $debug "DEBUG: $*"; }


######
# Error Usage Hook

# error_usage() - Prints an error ($*) and current command usage.
error_usage() { $error_usage_hook "$@"; }

# error_usage_stub() - This stub prints an unadorned error; the
# `core/commands`_ library provides a version to print the usage
# information.
#
# .. _core/commands: ../core/commands.html
error_usage_stub() { error "$1"; }


######
# Assertions

_assert() {
	local _efunc=$1
	local _err=$2
	shift 2
	"$@" || $_efunc "$_err"
}

# assert() - Calls ``error()`` with a message ($1) if a command ($@)
# does not return success.
assert() { _assert error "$@"; }

# assert_usage() - Same as ``assert()`` but calls ``error_usage()``
# instead of ``error()``.
assert_usage() { _assert error_usage "$@"; }


######
# Stack Traces

# stack_raw() - Prints the current stack in its raw form: the built-in
# variables that describe it.
stack_raw() {
	echo "FUNCNAME=( ${FUNCNAME[*]} )"
	echo "BASH_SOURCES=( ${BASH_SOURCE[*]} )"
	echo "BASH_LINENO=( ${BASH_LINENO[*]} )"
}

# stack_trace() - Prints the current stack, if ``$debug`` is `true`.
stack_trace() {
	debug "Stack trace:"
	local depth="${#FUNCNAME[@]}"
	for_each _stack_dump $(seq 2 $(($depth - 1)))
}

_stack_dump() {
	local frame=$1
	local func="${FUNCNAME[$frame]}"
	local file=${BASH_SOURCE[$frame]}
	file=${file#$libdir/}
	file=${file%.sh}
	local lineno="${BASH_LINENO[$(($frame - 1))]}"
	debug "$((frame - 2)): $func ($file:$lineno)"
}

View the Developer Guide Index

View the Reference Manual Index


Generated on Fri Jul 28 14:35:00 PDT 2017 by mcsh d14 v0.23.0.