fix bug after a bash completion
[errhandle.git] / err
diff --git a/err b/err
index f6a7042eb0f5b0dd644b4829b881cc6aee92a999..5d15407638146dedb81aa36783940e8efb8edcf4 100644 (file)
--- a/err
+++ b/err
@@ -1,18 +1,6 @@
 #!/bin/bash
-# Copyright 2018 Ian Kelling
-
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-
-# http://www.apache.org/licenses/LICENSE-2.0
-
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
+# Copyright (C) 2019 Ian Kelling
+# SPDX-License-Identifier: GPL-3.0-or-later
 
 # Commentary: Bash stack trace and error handling functions. This file
 # is meant to be sourced. It loads some functions which you may want to
@@ -66,10 +54,17 @@ err-bash-trace() {
 # On error print stack trace and exit
 #
 # Globals:
-#   ${_errcatch_cleanup[@]}  Optional command & args that will run before exiting
+#   errcatch-cleanup  If set, this command will run just before exiting.
 #######################################
 err-catch() {
-  set -E; shopt -s extdebug
+  set -E;
+  # This condition avoids starting the bash debugger in the case that
+  # this is sourced from a startup file, and you use a login shell to
+  # run a command. eg: bash -l some-command. Avoid doing that if you want
+  # function arguments in your trace.
+  if ! shopt login_shell >/dev/null; then
+    shopt -s extdebug
+  fi
   _err-trap() {
     err=$?
     exec >&2
@@ -82,10 +77,9 @@ err-catch() {
       echo "$msg"
     fi
     set -e # err trap does not work within an error trap
-    # note :-: makes this compatible with set -u, assigns : if unset, but shellcheck
-    # doesn't understand that.
-    # shellcheck disable=SC2154
-    "${_errcatch_cleanup[@]:-:}"
+    if type -t errcatch-cleanup >/dev/null; then
+      errcatch-cleanup
+    fi
     echo "$0: exiting with status $err"
     exit $err
   }
@@ -94,46 +88,84 @@ err-catch() {
 }
 
 
+#######################################
+# Internal function for err-catch-interactive.
+# Prints stack trace from interactive shell trap.
+# Usage: see err-catch-interactive
+#######################################
+
+_err-bash-trace-interactive() {
+  if (( ${#FUNCNAME[@]} <= 1 )); then
+    return 0
+  fi
+
+  for pattern in "${err_catch_ignore[@]}"; do
+    # shellcheck disable=SC2053
+    if [[ ${BASH_SOURCE[1]} == $pattern ]]; then
+      return 0
+    fi
+  done
+
+  local ret bash_command argc pattern i last
+  last=$_err_func_last
+  _err_func_last=${#FUNCNAME[@]}
+  # We have these passed to us because they are lost inside the
+  # function.
+  ret=$1
+  bash_command="$2"
+  argc=$(( $3 - 1 ))
+  shift 3
+  argv=("$@")
+  # The trap returns a nonzero, then gets called again. This condition
+  # tells us if we are the first.
+  if (( _err_func_last > last  )); then
+    echo ERR: \`$bash_command\' returned $ret
+  fi
+  printf "  from \`%s" "${FUNCNAME[1]}"
+  if shopt extdebug >/dev/null; then
+    for ((i=argc; i >= 0; i--)); do
+      printf " %s" "${argv[i]}"
+    done
+  fi
+  printf "\' defined at %s:%s\n" "${BASH_SOURCE[1]}" "$(declare -F "${FUNCNAME[1]}"|awk "{print \$2}")"
+  return $ret
+}
+
 #######################################
 # For interactive shells: on error, print stack trace and return
 #
+# Note: calling line number is not available, so we print function
+# definition lines.
+#
 # Globals:
-#   _err_func_last  Used internally.
-#   _err_catch_err  Used internally.
-#   _err_catch_i    Used internally.
+#   err_catch_ignore  Array containing glob patterns to test against filenames to ignore
+#                     errors from. Initialized to ignore bash-completion scripts on debian
+#                     based systems.
+#   _err_func_last    Used internally in err-bash-trace-interactive
 #
-# misc: All shellcheck disables for this function are false positives.
 #######################################
-# shellcheck disable=SC2120
 err-catch-interactive() {
-  # shellcheck disable=SC2034
+  if ! test ${err_catch_ignore+defined}; then
+    err_catch_ignore=(
+      '/etc/bash_completion.d/*'
+      '*/bash-completion/*'
+    )
+  fi
   declare -i _err_func_last=0
   set -E; shopt -s extdebug
   # shellcheck disable=SC2154
-  trap '_err_catch_err=$? _trap_bc="$BASH_COMMAND"
-  if (( ${#FUNCNAME[@]} > _err_func_last )); then
-    echo ERR: \`$_trap_bc'"\'"' returned $_err_catch_err
-  fi
-  _err_func_last=${#FUNCNAME[@]}
-  if (( _err_func_last )); then
-    printf "  from %s:%s:in \`%s" "${BASH_SOURCE[0]}" "$(declare -F "${FUNCNAME[0]}"|awk "{print \$2}")" "${FUNCNAME[0]}"
-    if shopt extdebug >/dev/null; then
-      for ((_err_catch_i=${BASH_ARGC[0]}-1; _err_catch_i >= 0; _err_catch_i--)); do
-        printf " %s" "${BASH_ARGV[_err_catch_i]}"
-      done
-    fi
-    echo '"\'"'
-    return $_err_catch_err
-  fi' ERR
+  trap '_err-bash-trace-interactive $? "$BASH_COMMAND" ${BASH_ARGC[0]} "${BASH_ARGV[@]}" || return $?' ERR
   set -o pipefail
 }
 
 
 #######################################
-# Undoes err-catch. turns off exit and stack trace on error.
+# Undo err-catch/err-catch-interactive
 #######################################
 err-allow() {
-  set +E +o pipefail; trap ERR
+  shopt -u extdebug
+  set +E +o pipefail
+  trap ERR
 }
 
 #######################################