>> ... >> >> I'd like to see your code. I'm not sure about that :-) >> ... >> University of Utah.., I'd like to visit SLC again someday. >> Last time I couldn't speak English at all. >> My ability has been improved a bit since then. >> ... Not to worry. Most people around the university are foreigners (German, Polish, Russian, Chinese, ...), and a little English goes a long way. >> Could you post it to the list please? Sure. Here it is. # # $Id: mydebug.rb,v 1.2 1999/07/13 17:19:34 install Exp install $ # def max(a,b) if (a<b); b; else a; end end def min(a,b) if (a<=b); a; else b; end end class DEBUGGER__ trap("INT") { DEBUGGER__::CONTEXT.interrupt } $DEBUG = TRUE def initialize @break_points = [] @stop_next = 1 @frames = [nil] @frame_pos = nil @last_file = nil @scripts = {} end DEBUG_LAST_CMD = [] def interrupt @stop_next = 1 end def debug_eval(str, binding) begin val = eval(str, binding) val rescue at = caller(0) printf "%s:%s\n", at.shift, $! for i in at break if i =~ /`debug_(eval|command)'$/ #` printf "\tfrom %s\n", i end end end def debug_command(file, line, id, binding) if (ENV['EMACS'] == 't') printf "\032\032%s:%d:\n", file, line else printf "%s:%d:%s", file, line, line_at(file, line) end @frames[-1] = binding STDOUT.print "(rdb:-) " STDOUT.flush while input = STDIN.gets input.chop! if input == "" input = DEBUG_LAST_CMD[0] else DEBUG_LAST_CMD[0] = input end case input when /^b(reak)?\s+(([^:\n]+:)?.+)/ pos = $2 if pos.index ":" file, pos = pos.split(":") end file = File.basename(file) if pos =~ /^\d+$/ pname = pos pos = Integer(pos) else pname = pos = pos.intern.id2name end printf "Set breakpoint %d at %s:%s\n", @break_points.size, file, pname @break_points.push [file, pos] when /^b(reak)?$/ n = 0 for f, p in @break_points printf "%d %s:%s\n", n, f, p n += 1 end when /^del(ete)?(\s+(\d+))?$/ pos = $3 unless pos STDOUT.print "clear all breakpoints? (y/n) " STDOUT.flush input = STDIN.gets.chop! if input == "y" for n in @break_points.indexes @break_points[n] = nil end end else pos = Integer(pos) if @break_points[pos] bp = @break_points[pos] printf "Clear breakpoint %d at %s:%s\n", pos, bp[0], bp[1] @break_points[pos] = nil else printf "Breakpoint %d is not defined\n", pos end end when /^c(ont)?$/ return when /^s(tep)?\s*(\d+)?$/ if $2 lev = Integer($2) else lev = 1 end @stop_next = lev return when /^n(ext)?\s*(\d+)?$/ if $2 lev = Integer($2) else lev = 1 end @stop_next = lev @no_step = @frames.size return when /^i(?:nfo)?/, /^w(?:here)?/ fs = @frames.size tb = caller(0)[-fs..-1].reverse unless @frame_pos; @frame_pos = fs - 1; end (fs-1).downto(0){ |i| if (@frame_pos == i) printf "--> frame %d:%s\n", i, tb[i] else printf " frame %d:%s\n", i, tb[i] end } when /^l(ist)?$/ fs = @frames.size tb = caller(0)[-fs..-1].reverse unless @frame_pos; @frame_pos = fs - 1; end file, line, func = tb[@frame_pos].split(":") line = line.to_i b = line - 1 e = line + 9 line_at(file, line) if lines = @scripts[file] and lines != TRUE lines = [0] + lines # Simple offset adjust b = max(0, b); e = min(lines.size-1, e) for l in b..e if (l == line) printf "--> %5d %s", l, lines[l] else printf " %5d %s", l, lines[l] end end else printf "no sourcefile available for %s\n", file end when /^d(?:own)?\s*(\d+)??$/ if $1; lev = Integer($1); else lev = 1; end unless @frame_pos; @frame_pos = 0; end @frame_pos -= lev if @frame_pos < 0 STDOUT.print "at level 0 (bottom)\n" @frame_pos = 0 else STDOUT.printf "at level %d\n", @frame_pos end binding = @frames[@frame_pos] when /^u(?:p)?\s*(\d+)?$/ if $1; lev = Integer($1); else lev = 1; end unless @frame_pos; @frame_pos = @frames.size - 1 ; end @frame_pos += lev if @frame_pos >= @frames.size @frame_pos = @frames.size - 1 printf "at level %d (top)\n", @frame_pos else STDOUT.printf "at level %d\n", @frame_pos end binding = @frames[@frame_pos] when /^f(inish)?/ @finish_pos = @frames.size return when /^q(uit)?$/ STDOUT.print "really quit? (y/n) " STDOUT.flush input = STDIN.gets.chop! exit if input == "y" when /^p\s+/ p debug_eval($', binding) #' else v = debug_eval(input, binding) p v unless v == nil end STDOUT.print "(rdb:-) " STDOUT.flush end end def line_at(file, line) lines = @scripts[file] if lines return "\n" if lines == TRUE line = lines[line-1] return "\n" unless line return line end save = $DEBUG begin $DEBUG = FALSE f = open(file) lines = @scripts[file] = f.readlines rescue $DEBUG = save @scripts[file] = TRUE return "\n" end line = lines[line-1] return "\n" unless line return line end def debug_funcname(id) if id == 0 "toplevel" else id.id2name end end def check_break_points(file, pos, binding, id) file = File.basename(file) if @break_points.include? [file, pos] index = @break_points.index([file, pos]) printf "Breakpoint %d, %s at %s:%s\n", index, debug_funcname(id), file, pos return TRUE end return FALSE end def excn_handle(file, line, id, binding) fs = @frames.size tb = caller(0)[-fs..-1] unless @frame_pos; @frame_pos = fs - 1; end printf "%s\n", $! for i in tb printf "\tfrom %s\n", i end debug_command(file, line, id, binding) end def trace_func(event, file, line, id, binding) if event == 'line' if @no_step == nil or @no_step >= @frames.size @stop_next -= 1 end if @stop_next == 0 if [file, line] == @last @stop_next = 1 else @no_step = nil debug_command(file, line, id, binding) @last = [file, line] end end if check_break_points(file, line, binding, id) debug_command(file, line, id, binding) end end if event == 'call' @frames.push binding if check_break_points(file, id.id2name, binding, id) debug_command(file, line, id, binding) end end if event == 'class' @frames.push binding end if event == 'return' or event == 'end' if @finish_pos == @frames.size @stop_next = 1 end @frames.pop end if event == 'raise' # @frames.push binding excn_handle(file, line, id, binding) end @last_file = file end CONTEXT = new end set_trace_func proc{|event, file, line, id, binding,*rest| DEBUGGER__::CONTEXT.trace_func event, file, line, id, binding }