#!/bin/bash
#  shell - Shell script support

set -e


######
# Settings

sys_shell_config_init() {
	lib_setting_vars shell_is_running shell_is_interactive
}

sys_shell_config_check() {
	shell_is_running=false
	shell_is_interactive=false
}

######
# Internal functions

terminal_is_interactive() {
	case "$-" in
	(*i*) true ;;
	(*) false ;;
	esac
}

shell_readline() {
	local path=${PWD/$HOME/\~}
	read -p "$(timestamp) $path $script_name> " -e line
}

shell_eval() {
	local result=0
	eval "$@" || result=$?
	if [ $result -ne 0 ]; then
		app_echo "shell command failed: $result"
		shell_is_running=$shell_is_interactive
	fi
}

shell_native() {
	local -a shell_line_args=( "$@" )
	shell_line_args[0]=${1#!}
	shell_eval "${shell_line_args[@]}"
}

shell_builtin() {
	case "$1" in
	(!*) shell_native "$@"; return 0 ;;
	(*=*) ;;
	([[]) ;;
	(history|cd|ls|mv|cp|mkdir|rm|rmdir|xargs) ;;
	(test|echo|pushd|popd|sed|grep|find) ;;
	(declare|typeset|set|unset|alias|unalias) ;;
	(read|readarray) ;;
	(error|warn|info|app_echo) ;;
	(*) return 1
	esac
	shell_eval "$@"
	true
}

shell_app_builtin() {
	case "$1" in
	q|quit|x|exit)		shell_is_running=false; return 0 ;;
	mcsh_load)		lib_load "$2" ;;
	mcsh_version)		app_version; true ;;
	mcsh_restart)		exec $0; exit ;;
	*)			return 1 ;;
	esac
}

shell_dispatch() {
	local result=0
	eval script_cmd_dispatch "$@" || result=$?
	if [ $result -ne 0 ]; then
		app_echo "command failed: $result"
		shell_is_running=$shell_is_interactive
	fi
}

######
# Public interface

shell_run_core() {
	info "shell $*: starting..."

	local line buffered
	while $shell_is_running && shell_readline; do
		[ "$line" ] || continue
		if [ "${line%\\}" != "$line" ]; then
			buffered="$buffered${line%\\}"
			continue
		elif [ "$buffered" ]; then
			line="$buffered$line"
			buffered=""
		fi
		history -s "$line"

		local cmd="${line%%#*}"
		[ "$cmd" ] || continue

		! shell_builtin $line || continue
		! shell_app_builtin $line || continue
		! shell_dispatch $line || continue
		# halt if the shell is not interactive
		$shell_is_interactive

		local -a shell_line_args=( $line )
		echo "error: $line_args: command not found"
	done

	info "shell $*: ... done!"
}

shell_run_file() {
	$shell_is_running || return
	info "$1: script executing..."
	local args=( "$@" )
	shell_run_core "$@" <$1
	info "$1: ... done"
}

shell_run() {
	! $shell_is_running || error "shell: recursion is not supported!"
	shell_is_running=true
	file_is_terminal stdin && app_version
	if [ "$*" ]; then
		shell_is_interactive=false
		shell_run_file "$@"
	else
		shell_is_interactive=true
		shell_run_core
	fi
	shell_is_running=false
}

shell_help() {
	cat <<EOF
${script[*]} reads commands from standard input

Standard input can be either an interactive terminal or a pipe.
If input comes from a terminal, a prompt will be displayed.
EOF
}

View the Developer Guide Index

View the Reference Manual Index


Generated on Fri Jul 28 14:36:04 PDT 2017 by mcsh d14 v0.23.0.