| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | #! /bin/bash | 
					
						
							|  |  |  | # bashdb - Bash shell debugger | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Adapted from an idea in O'Reilly's `Learning the Korn Shell' | 
					
						
							|  |  |  | # Copyright (C) 1993-1994 O'Reilly and Associates, Inc. | 
					
						
							|  |  |  | # Copyright (C) 1998, 1999, 2001 Gary V. Vaughan <gvv@techie.com>> | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  | # it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | # the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  | # (at your option) any later version. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program is distributed in the hope that it will be useful, but | 
					
						
							|  |  |  | # WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  | # General Public License for more details. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | # along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # As a special exception to the GNU General Public License, if you | 
					
						
							|  |  |  | # distribute this file as part of a program that contains a | 
					
						
							|  |  |  | # configuration script generated by Autoconf, you may include it under | 
					
						
							|  |  |  | # the same distribution terms that you use for the rest of that program. | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | # NOTE: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # This program requires bash 2.x. | 
					
						
							|  |  |  | # If bash 2.x is installed as "bash2", you can invoke  bashdb like this: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #   DEBUG_SHELL=/bin/bash2 /bin/bash2 bashdb script.sh | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | # TODO: | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # break [regexp] | 
					
						
							|  |  |  | # cond [break] [condition] | 
					
						
							|  |  |  | # tbreak [regexp|+lines] | 
					
						
							|  |  |  | # restart | 
					
						
							|  |  |  | # Variable watchpoints | 
					
						
							|  |  |  | # Instrument `source' and `.' files in $_potbelliedpig | 
					
						
							|  |  |  | # be cleverer about lines we allow breakpoints to be set on | 
					
						
							|  |  |  | # break [function_name] | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | echo 'Bash Debugger version 1.2.4' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export _dbname=${0##*/} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if test $# -lt 1; then | 
					
						
							|  |  |  |   echo "$_dbname: Usage: $_dbname filename" >&2 | 
					
						
							|  |  |  |   exit 1 | 
					
						
							|  |  |  | fi | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | _guineapig=$1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | if test ! -r $1; then | 
					
						
							|  |  |  |   echo "$_dbname: Cannot read file '$_guineapig'." >&2 | 
					
						
							|  |  |  |   exit 1 | 
					
						
							|  |  |  | fi | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | shift | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | __debug=${TMPDIR-/tmp}/bashdb.$$ | 
					
						
							|  |  |  | sed -e '/^# bashdb - Bash shell debugger/,/^# -- DO NOT DELETE THIS LINE -- /d' "$0" > $__debug | 
					
						
							|  |  |  | cat $_guineapig >> $__debug | 
					
						
							|  |  |  | exec ${DEBUG_SHELL-bash} $__debug $_guineapig "$@" | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | exit 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # -- DO NOT DELETE THIS LINE -- The program depends on it | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #bashdb preamble | 
					
						
							|  |  |  | # $1 name of the original guinea pig script | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __debug=$0 | 
					
						
							|  |  |  | _guineapig=$1 | 
					
						
							|  |  |  | __steptrap_calls=0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | shift | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | shopt -s extglob	# turn on extglob so we can parse the debugger funcs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _steptrap | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i=0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _curline=$1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (( ++__steptrap_calls > 1 && $_curline == 1 )); then | 
					
						
							|  |  |  |     return | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [ -n "$_disps" ]; then | 
					
						
							|  |  |  |     while (( $i < ${#_disps[@]} )) | 
					
						
							|  |  |  |     do | 
					
						
							|  |  |  |       if [ -n "${_disps[$i]}" ]; then | 
					
						
							|  |  |  |         _msg "${_disps[$i]}: \c" | 
					
						
							|  |  |  |         eval _msg ${_disps[$i]} | 
					
						
							|  |  |  |       fi | 
					
						
							|  |  |  |       let i=$i+1 | 
					
						
							|  |  |  |     done | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (( $_trace )); then | 
					
						
							|  |  |  |     _showline $_curline | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (( $_steps >= 0 )); then | 
					
						
							|  |  |  |     let _steps="$_steps - 1" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if _at_linenumbp ; then | 
					
						
							|  |  |  |     _msg "Reached breakpoint at line $_curline" | 
					
						
							|  |  |  |     _showline $_curline | 
					
						
							|  |  |  |     _cmdloop | 
					
						
							|  |  |  |   elif [ -n "$_brcond" ] && eval $_brcond; then | 
					
						
							|  |  |  |     _msg "Break condition $_brcond true at line $_curline" | 
					
						
							|  |  |  |     _showline $_curline | 
					
						
							|  |  |  |     _cmdloop | 
					
						
							|  |  |  |   elif (( $_steps == 0 )); then | 
					
						
							|  |  |  |     # Assuming a real script will have the "#! /bin/sh" at line 1, | 
					
						
							|  |  |  |     # assume that when $_curline == 1 we are inside backticks. | 
					
						
							|  |  |  |     if (( ! $_trace )); then | 
					
						
							|  |  |  |       _msg "Stopped at line $_curline" | 
					
						
							|  |  |  |       _showline $_curline | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |     _cmdloop | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _setbp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i f line _x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [ -z "$1" ]; then | 
					
						
							|  |  |  |     _listbp | 
					
						
							|  |  |  |     return | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   eval "$_seteglob" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [[ $1 == *(\+)[1-9]*([0-9]) ]]; then | 
					
						
							|  |  |  |     case $1 in | 
					
						
							|  |  |  |     +*) | 
					
						
							|  |  |  |       # normalize argument, then double it (+2 -> +2 + 2 = 4) | 
					
						
							|  |  |  |       _x=${1##*([!1-9])}	# cut off non-numeric prefix | 
					
						
							|  |  |  |       _x=${x%%*([!0-9])}	# cut off non-numeric suffix | 
					
						
							|  |  |  |       f=$(( $1 + $_x )) | 
					
						
							|  |  |  |       ;; | 
					
						
							|  |  |  |     *) | 
					
						
							|  |  |  |       f=$(( $1 )) | 
					
						
							|  |  |  |       ;; | 
					
						
							|  |  |  |     esac | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # find the next valid line | 
					
						
							|  |  |  |     line="${_lines[$f]}" | 
					
						
							|  |  |  |     while _invalidbreakp $f | 
					
						
							|  |  |  |     do | 
					
						
							|  |  |  |       (( f++ )) | 
					
						
							|  |  |  |       line="${_lines[$f]}" | 
					
						
							|  |  |  |     done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (( $f != $1 )) | 
					
						
							|  |  |  |     then | 
					
						
							|  |  |  |       _msg "Line $1 is not a valid breakpoint" | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if [ -n "${_lines[$f]}" ]; then | 
					
						
							|  |  |  |       _linebp[$1]=$1; | 
					
						
							|  |  |  |       _msg "Breakpoint set at line $f" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       _msg "Breakpoints can only be set on executable lines" | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _msg "Please specify a numeric line number" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   eval "$_resteglob" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _listbp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if [ -n "$_linebp" ]; then | 
					
						
							|  |  |  |     _msg "Breakpoints:" | 
					
						
							|  |  |  |     for i in ${_linebp[*]}; do | 
					
						
							|  |  |  |       _showline $i | 
					
						
							|  |  |  |     done | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _msg "No breakpoints have been set" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _clearbp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [ -z "$1" ]; then | 
					
						
							|  |  |  |     read -e -p "Delete all breakpoints? " | 
					
						
							|  |  |  |     case $REPLY in | 
					
						
							|  |  |  |     [yY]*) | 
					
						
							|  |  |  |       unset _linebp[*] | 
					
						
							|  |  |  |       _msg "All breakpoints have been cleared" | 
					
						
							|  |  |  |       ;; | 
					
						
							|  |  |  |     esac | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   eval "$_seteglob" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [[ $1 == [1-9]*([0-9]) ]]; then | 
					
						
							|  |  |  |     unset _linebp[$1] | 
					
						
							|  |  |  |     _msg "Breakpoint cleared at line $1" | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _msg "Please specify a numeric line number" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   eval "$_resteglob" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _setbc | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (( $# > 0 )); then | 
					
						
							|  |  |  |     _brcond=$@ | 
					
						
							|  |  |  |     _msg "Break when true: $_brcond" | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _brcond= | 
					
						
							|  |  |  |     _msg "Break condition cleared" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _setdisp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if [ -z "$1" ]; then | 
					
						
							|  |  |  |     _listdisp | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _disps[${#_disps[@]}]="$1" | 
					
						
							|  |  |  |     if (( ${#_disps[@]} < 10 )) | 
					
						
							|  |  |  |     then | 
					
						
							|  |  |  |       _msg " ${#_disps[@]}: $1" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       _msg "${#_disps[@]}: $1" | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _listdisp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i=0 j | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if [ -n "$_disps" ]; then | 
					
						
							|  |  |  |     while (( $i < ${#_disps[@]} )) | 
					
						
							|  |  |  |     do | 
					
						
							|  |  |  |       let j=$i+1 | 
					
						
							|  |  |  |     if (( ${#_disps[@]} < 10 )) | 
					
						
							|  |  |  |     then | 
					
						
							|  |  |  |       _msg " $j: ${_disps[$i]}" | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       _msg "$j: ${_disps[$i]}" | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |       let i=$j | 
					
						
							|  |  |  |     done | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _msg "No displays have been set" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _cleardisp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if (( $# < 1 )) ; then | 
					
						
							|  |  |  |     read -e -p "Delete all display expressions? " | 
					
						
							|  |  |  |     case $REPLY in | 
					
						
							|  |  |  |     [Yy]*) | 
					
						
							|  |  |  |       unset _disps[*] | 
					
						
							|  |  |  |       _msg "All breakpoints have been cleared" | 
					
						
							|  |  |  |       ;; | 
					
						
							|  |  |  |     esac | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   eval "$_seteglob" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [[ $1 == [1-9]*([0-9]) ]]; then | 
					
						
							|  |  |  |     unset _disps[$1] | 
					
						
							|  |  |  |     _msg "Display $i has been cleared" | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _listdisp | 
					
						
							|  |  |  |     _msg "Please specify a numeric display number" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   eval "$_resteglob" | 
					
						
							|  |  |  | }    | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # usage _ftrace -u funcname [funcname...] | 
					
						
							|  |  |  | function _ftrace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local _opt=-t _tmsg="enabled" _func  | 
					
						
							|  |  |  |   if [[ $1 == -u ]]; then | 
					
						
							|  |  |  | 	_opt=+t | 
					
						
							|  |  |  | 	_tmsg="disabled" | 
					
						
							|  |  |  | 	shift | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  |   for _func; do | 
					
						
							|  |  |  | 	  declare -f $_opt $_func | 
					
						
							|  |  |  | 	  _msg "Tracing $_tmsg for function $_func" | 
					
						
							|  |  |  |   done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _cmdloop | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local cmd args | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while read -e -p "bashdb> " cmd args; do | 
					
						
							|  |  |  |     test -n "$cmd" && history -s "$cmd $args"	# save on history list | 
					
						
							|  |  |  |     test -n "$cmd" || { set $_lastcmd; cmd=$1; shift; args=$*; } | 
					
						
							|  |  |  |     if [ -n "$cmd" ] | 
					
						
							|  |  |  |     then | 
					
						
							|  |  |  |       case $cmd in | 
					
						
							|  |  |  | 	b|br|bre|brea|break) | 
					
						
							|  |  |  | 	  _setbp $args | 
					
						
							|  |  |  | 	  _lastcmd="break $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	co|con) | 
					
						
							|  |  |  | 	  _msg "ambiguous command: '$cmd', condition, continue?" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	cond|condi|condit|conditi|conditio|condition) | 
					
						
							|  |  |  | 	  _setbc $args | 
					
						
							|  |  |  | 	  _lastcmd="condition $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	c|cont|conti|contin|continu|continue) | 
					
						
							|  |  |  | 	  _lastcmd="continue" | 
					
						
							|  |  |  | 	  return | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	d) | 
					
						
							|  |  |  | 	  _msg "ambiguous command: '$cmd', delete, display?" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	de|del|dele|delet|delete) | 
					
						
							|  |  |  | 	  _clearbp $args | 
					
						
							|  |  |  | 	  _lastcmd="delete $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	di|dis|disp|displ|displa|display) | 
					
						
							|  |  |  | 	  _setdisp $args | 
					
						
							|  |  |  | 	  _lastcmd="display $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	f|ft|ftr|ftra|ftrace) | 
					
						
							|  |  |  | 	  _ftrace $args | 
					
						
							|  |  |  | 	  _lastcmd="ftrace $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	\?|h|he|hel|help) | 
					
						
							|  |  |  | 	  _menu | 
					
						
							|  |  |  | 	  _lastcmd="help" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	l|li|lis|list) | 
					
						
							|  |  |  | 	  _displayscript $args | 
					
						
							|  |  |  | 	  # _lastcmd is set in the _displayscript function | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	p|pr|pri|prin|print) | 
					
						
							|  |  |  | 	  _examine $args | 
					
						
							|  |  |  | 	  _lastcmd="print $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	q|qu|qui|quit) | 
					
						
							|  |  |  | 	  exit | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	s|st|ste|step|n|ne|nex|next) | 
					
						
							|  |  |  | 	  let _steps=${args:-1} | 
					
						
							|  |  |  | 	  _lastcmd="next $args" | 
					
						
							|  |  |  | 	  return | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	t|tr|tra|trac|trace) | 
					
						
							|  |  |  | 	  _xtrace | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	u|un|und|undi|undis|undisp|undispl|undispla|undisplay) | 
					
						
							|  |  |  | 	  _cleardisp $args | 
					
						
							|  |  |  | 	  _lastcmd="undisplay $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	!*) | 
					
						
							|  |  |  | 	  eval ${cmd#!} $args | 
					
						
							|  |  |  | 	  _lastcmd="$cmd $args" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  | 	*) | 
					
						
							|  |  |  | 	  _msg "Invalid command: '$cmd'" | 
					
						
							|  |  |  | 	  ;; | 
					
						
							|  |  |  |       esac | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |   done | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _at_linenumbp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   [[ -n ${_linebp[$_curline]} ]] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _invalidbreakp | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local line=${_lines[$1]} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # XXX - should use shell patterns | 
					
						
							|  |  |  |   if test -z "$line" \ | 
					
						
							|  |  |  |       || expr "$line" : '[ \t]*#.*' > /dev/null \ | 
					
						
							|  |  |  |       || expr "$line" : '[ \t]*;;[ \t]*$' > /dev/null \ | 
					
						
							|  |  |  |       || expr "$line" : '[ \t]*[^)]*)[ \t]*$' > /dev/null \ | 
					
						
							|  |  |  |       || expr "$line" : '[ \t]*;;[ \t]*#.**$' > /dev/null \ | 
					
						
							|  |  |  |       || expr "$line" : '[ \t]*[^)]*)[ \t]*;;[ \t]*$' > /dev/null \ | 
					
						
							|  |  |  |       || expr "$line" : '[ \t]*[^)]*)[ \t]*;;*[ \t]*#.*$' > /dev/null | 
					
						
							|  |  |  |   then | 
					
						
							|  |  |  |     return 0 | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return 1 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _examine | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if [ -n "$*" ]; then | 
					
						
							|  |  |  |     _msg "$args: \c" | 
					
						
							|  |  |  |     eval _msg $args | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _msg "Nothing to print" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _displayscript | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i j start end bp cl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (( $# == 1 )); then	# list 5 lines on either side of $1 | 
					
						
							|  |  |  |     if [ $1 = "%" ]; then | 
					
						
							|  |  |  |       let start=1 | 
					
						
							|  |  |  |       let end=${#_lines[@]} | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let start=$1-5 | 
					
						
							|  |  |  |       let end=$1+5 | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |   elif (( $# > 1 )); then	# list between start and end | 
					
						
							|  |  |  |     if [ $1 = "^" ]; then | 
					
						
							|  |  |  |       let start=1 | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let start=$1 | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if [ $2 = "\$" ]; then | 
					
						
							|  |  |  |       let end=${#_lines[@]} | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |       let end=$2 | 
					
						
							|  |  |  |     fi | 
					
						
							|  |  |  |   else				# list 5 lines on either side of current line | 
					
						
							|  |  |  |     let start=$_curline-5 | 
					
						
							|  |  |  |     let end=$_curline+5 | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # normalize start and end | 
					
						
							|  |  |  |   if (( $start < 1 )); then | 
					
						
							|  |  |  |     start=1 | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  |   if (( $end > ${#_lines[@]} )); then | 
					
						
							|  |  |  |     end=${#_lines[@]} | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cl=$(( $end - $start )) | 
					
						
							|  |  |  |   if (( $cl > ${LINES-24} )); then | 
					
						
							|  |  |  |     pager=${PAGER-more} | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     pager=cat | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   i=$start | 
					
						
							|  |  |  |   ( while (( $i <= $end )); do | 
					
						
							|  |  |  |       _showline $i | 
					
						
							|  |  |  |       let i=$i+1 | 
					
						
							|  |  |  |     done ) 2>&1 | $pager | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   # calculate the next block of lines | 
					
						
							|  |  |  |   start=$(( $end + 1 )) | 
					
						
							|  |  |  |   end=$(( $start + 11 )) | 
					
						
							|  |  |  |   if (( $end > ${#_lines[@]} )) | 
					
						
							|  |  |  |   then | 
					
						
							|  |  |  |     end=${#_lines[@]} | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _lastcmd="list $start $end" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _xtrace | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   let _trace="! $_trace" | 
					
						
							|  |  |  |   if (( $_trace )); then | 
					
						
							|  |  |  |     _msg "Execution trace on" | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     _msg "Execution trace off" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | function _msg | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   echo -e "$@" >&2 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _showline | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   local i=0 bp=' ' line=$1 cl=' ' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if [[ -n ${_linebp[$line]} ]]; then | 
					
						
							|  |  |  |     bp='*' | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if  (( $_curline == $line )); then | 
					
						
							|  |  |  |     cl=">" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (( $line < 100 )); then | 
					
						
							|  |  |  |     _msg "${_guineapig/*\//}:$line   $bp $cl${_lines[$line]}" | 
					
						
							|  |  |  |   elif (( $line < 10 )); then | 
					
						
							|  |  |  |     _msg "${_guineapig/*\//}:$line  $bp $cl${_lines[$line]}" | 
					
						
							|  |  |  |   elif (( $line > 0 )); then | 
					
						
							|  |  |  |     _msg "${_guineapig/*\//}:$line $bp $cl${_lines[$line]}" | 
					
						
							|  |  |  |   fi | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _cleanup | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   rm -f $__debug $_potbelliedpig 2> /dev/null | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function _menu | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   _msg 'bashdb commands: | 
					
						
							|  |  |  | 	break N		set breakpoint at line N | 
					
						
							|  |  |  | 	break		list breakpoints & break condition | 
					
						
							|  |  |  | 	condition foo	set break condition to foo | 
					
						
							|  |  |  | 	condition	clear break condition | 
					
						
							|  |  |  | 	delete N	clear breakpoint at line N | 
					
						
							|  |  |  | 	delete		clear all breakpoints | 
					
						
							|  |  |  | 	display EXP	evaluate and display EXP for each debug step | 
					
						
							|  |  |  | 	display		show a list of display expressions | 
					
						
							|  |  |  | 	undisplay N	remove display expression N | 
					
						
							|  |  |  | 	list N M        display all lines of script between N and M | 
					
						
							|  |  |  | 	list N          display 5 lines of script either side of line N | 
					
						
							|  |  |  | 	list		display 5 lines if script either side of current line | 
					
						
							|  |  |  | 	continue	continue execution upto next breakpoint | 
					
						
							|  |  |  | 	next [N]	execute [N] statements (default 1) | 
					
						
							|  |  |  | 	print expr	prints the value of an expression | 
					
						
							|  |  |  | 	trace		toggle execution trace on/off | 
					
						
							|  |  |  | 	ftrace [-u] func	make the debugger step into function FUNC | 
					
						
							|  |  |  | 			(-u turns off tracing FUNC) | 
					
						
							|  |  |  | 	help		print this menu | 
					
						
							|  |  |  | 	! string	passes string to a shell | 
					
						
							|  |  |  | 	quit		quit' | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | shopt -u extglob | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HISTFILE=~/.bashdb_history | 
					
						
							|  |  |  | set -o history | 
					
						
							|  |  |  | set +H | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # strings to save and restore the setting of `extglob' in debugger functions | 
					
						
							|  |  |  | # that need it | 
					
						
							|  |  |  | _seteglob='local __eopt=-u ; shopt -q extglob && __eopt=-s ; shopt -s extglob' | 
					
						
							|  |  |  | _resteglob='shopt $__eopt extglob' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _linebp=() | 
					
						
							|  |  |  | let _trace=0 | 
					
						
							|  |  |  | let _i=1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Be careful about quoted newlines | 
					
						
							|  |  |  | _potbelliedpig=${TMPDIR-/tmp}/${_guineapig/*\//}.$$ | 
					
						
							|  |  |  | sed 's,\\$,\\\\,' $_guineapig > $_potbelliedpig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _msg "Reading source from file: $_guineapig" | 
					
						
							|  |  |  | while read; do | 
					
						
							|  |  |  |   _lines[$_i]=$REPLY | 
					
						
							|  |  |  |   let _i=$_i+1 | 
					
						
							|  |  |  | done < $_potbelliedpig | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | trap _cleanup EXIT | 
					
						
							|  |  |  | # Assuming a real script will have the "#! /bin/sh" at line 1, | 
					
						
							|  |  |  | # don't stop at line 1 on the first run | 
					
						
							|  |  |  | let _steps=1 | 
					
						
							|  |  |  | LINENO=-1 | 
					
						
							|  |  |  | trap '_steptrap $LINENO' DEBUG |