ruby-debug19 0.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +9 -0
- data/LICENSE +23 -0
- data/bin/rdebug +415 -0
- data/cli/ruby-debug.rb +176 -0
- data/cli/ruby-debug/command.rb +228 -0
- data/cli/ruby-debug/commands/breakpoints.rb +153 -0
- data/cli/ruby-debug/commands/catchpoint.rb +55 -0
- data/cli/ruby-debug/commands/condition.rb +49 -0
- data/cli/ruby-debug/commands/continue.rb +38 -0
- data/cli/ruby-debug/commands/control.rb +107 -0
- data/cli/ruby-debug/commands/display.rb +120 -0
- data/cli/ruby-debug/commands/edit.rb +48 -0
- data/cli/ruby-debug/commands/enable.rb +202 -0
- data/cli/ruby-debug/commands/eval.rb +176 -0
- data/cli/ruby-debug/commands/finish.rb +42 -0
- data/cli/ruby-debug/commands/frame.rb +301 -0
- data/cli/ruby-debug/commands/help.rb +56 -0
- data/cli/ruby-debug/commands/info.rb +469 -0
- data/cli/ruby-debug/commands/irb.rb +123 -0
- data/cli/ruby-debug/commands/kill.rb +51 -0
- data/cli/ruby-debug/commands/list.rb +94 -0
- data/cli/ruby-debug/commands/method.rb +84 -0
- data/cli/ruby-debug/commands/quit.rb +39 -0
- data/cli/ruby-debug/commands/reload.rb +40 -0
- data/cli/ruby-debug/commands/save.rb +90 -0
- data/cli/ruby-debug/commands/set.rb +237 -0
- data/cli/ruby-debug/commands/show.rb +253 -0
- data/cli/ruby-debug/commands/source.rb +36 -0
- data/cli/ruby-debug/commands/stepping.rb +81 -0
- data/cli/ruby-debug/commands/threads.rb +189 -0
- data/cli/ruby-debug/commands/tmate.rb +36 -0
- data/cli/ruby-debug/commands/trace.rb +57 -0
- data/cli/ruby-debug/commands/variables.rb +199 -0
- data/cli/ruby-debug/debugger.rb +5 -0
- data/cli/ruby-debug/helper.rb +69 -0
- data/cli/ruby-debug/interface.rb +232 -0
- data/cli/ruby-debug/processor.rb +474 -0
- data/rdbg.rb +33 -0
- metadata +122 -0
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            module Debugger
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              module ParseFunctions
         | 
| 4 | 
            +
                Position_regexp = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                # Parse 'str' of command 'cmd' as an integer between
         | 
| 7 | 
            +
                # min and max. If either min or max is nil, that
         | 
| 8 | 
            +
                # value has no bound.
         | 
| 9 | 
            +
                def get_int(str, cmd, min=nil, max=nil, default=1)
         | 
| 10 | 
            +
                  return default unless str
         | 
| 11 | 
            +
                  begin
         | 
| 12 | 
            +
                    int = Integer(str)
         | 
| 13 | 
            +
                    if min and int < min
         | 
| 14 | 
            +
                      print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
         | 
| 15 | 
            +
                      return nil
         | 
| 16 | 
            +
                    elsif max and int > max
         | 
| 17 | 
            +
                      print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
         | 
| 18 | 
            +
                      return nil
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                    return int
         | 
| 21 | 
            +
                  rescue
         | 
| 22 | 
            +
                    print "%s argument '%s' needs to be a number.\n" % [cmd, str]
         | 
| 23 | 
            +
                    return nil
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                # Return true if arg is 'on' or 1 and false arg is 'off' or 0.
         | 
| 28 | 
            +
                # Any other value raises RuntimeError.
         | 
| 29 | 
            +
                def get_onoff(arg, default=nil, print_error=true)
         | 
| 30 | 
            +
                  if arg.nil? or arg == ''
         | 
| 31 | 
            +
                    if default.nil?
         | 
| 32 | 
            +
                      if print_error
         | 
| 33 | 
            +
                        print "Expecting 'on', 1, 'off', or 0. Got nothing.\n"
         | 
| 34 | 
            +
                        raise RuntimeError
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
                      return default
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                  case arg.downcase
         | 
| 40 | 
            +
                  when '1', 'on'
         | 
| 41 | 
            +
                    return true
         | 
| 42 | 
            +
                  when '0', 'off'
         | 
| 43 | 
            +
                    return false
         | 
| 44 | 
            +
                  else
         | 
| 45 | 
            +
                    if print_error
         | 
| 46 | 
            +
                      print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s
         | 
| 47 | 
            +
                      raise RuntimeError
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                # Return 'on' or 'off' for supplied parameter. The parmeter should
         | 
| 53 | 
            +
                # be true, false or nil.
         | 
| 54 | 
            +
                def show_onoff(bool)
         | 
| 55 | 
            +
                  if not [TrueClass, FalseClass, NilClass].member?(bool.class)
         | 
| 56 | 
            +
                    return "??"
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
                  return bool ? 'on' : 'off'
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                # Return true if code is syntactically correct for Ruby.
         | 
| 62 | 
            +
                def syntax_valid?(code)
         | 
| 63 | 
            +
                  eval("BEGIN {return true}\n#{code}", nil, "", 0)
         | 
| 64 | 
            +
                rescue Exception
         | 
| 65 | 
            +
                  false
         | 
| 66 | 
            +
                end 
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
            end
         | 
| @@ -0,0 +1,232 @@ | |
| 1 | 
            +
            module Debugger  
         | 
| 2 | 
            +
              class Interface # :nodoc:
         | 
| 3 | 
            +
                attr_writer :have_readline  # true if Readline is available
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def initialize
         | 
| 6 | 
            +
                  @have_readline = false
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                # Common routine for reporting debugger error messages.
         | 
| 10 | 
            +
                # Derived classed may want to override this to capture output.
         | 
| 11 | 
            +
                def errmsg(*args)
         | 
| 12 | 
            +
                  if Debugger.annotate.to_i > 2
         | 
| 13 | 
            +
                    aprint 'error-begin'
         | 
| 14 | 
            +
                    print(*args)
         | 
| 15 | 
            +
                    aprint ''
         | 
| 16 | 
            +
                  else
         | 
| 17 | 
            +
                    print '*** '
         | 
| 18 | 
            +
                    print(*args)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
                
         | 
| 22 | 
            +
                # Format msg with gdb-style annotation header
         | 
| 23 | 
            +
                def afmt(msg, newline="\n")
         | 
| 24 | 
            +
                  "\032\032#{msg}#{newline}"
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def aprint(msg)
         | 
| 28 | 
            +
                  print afmt(msg)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              class LocalInterface < Interface # :nodoc:
         | 
| 34 | 
            +
                attr_accessor :command_queue
         | 
| 35 | 
            +
                attr_accessor :histfile
         | 
| 36 | 
            +
                attr_accessor :history_save
         | 
| 37 | 
            +
                attr_accessor :history_length
         | 
| 38 | 
            +
                attr_accessor :restart_file
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                unless defined?(FILE_HISTORY)
         | 
| 41 | 
            +
                  FILE_HISTORY = ".rdebug_hist"
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
                def initialize()
         | 
| 44 | 
            +
                  super
         | 
| 45 | 
            +
                  @command_queue = []
         | 
| 46 | 
            +
                  @have_readline = false
         | 
| 47 | 
            +
                  @history_save = true
         | 
| 48 | 
            +
                  # take gdb's default
         | 
| 49 | 
            +
                  @history_length = ENV["HISTSIZE"] ? ENV["HISTSIZE"].to_i : 256  
         | 
| 50 | 
            +
                  @histfile = File.join(ENV["HOME"]||ENV["HOMEPATH"]||".", 
         | 
| 51 | 
            +
                                        FILE_HISTORY)
         | 
| 52 | 
            +
                  open(@histfile, 'r') do |file|
         | 
| 53 | 
            +
                    file.each do |line|
         | 
| 54 | 
            +
                      line.chomp!
         | 
| 55 | 
            +
                      Readline::HISTORY << line
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
                  end if File.exist?(@histfile)
         | 
| 58 | 
            +
                  @restart_file = nil
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                def read_command(prompt)
         | 
| 62 | 
            +
                  readline(prompt, true)
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
                
         | 
| 65 | 
            +
                def confirm(prompt)
         | 
| 66 | 
            +
                  readline(prompt, false)
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
                def print(*args)
         | 
| 70 | 
            +
                  STDOUT.printf(*args)
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                def close
         | 
| 74 | 
            +
                end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                # Things to do before quitting
         | 
| 77 | 
            +
                def finalize
         | 
| 78 | 
            +
                  if Debugger.method_defined?("annotate") and Debugger.annotate.to_i > 2
         | 
| 79 | 
            +
                    print "\032\032exited\n\n" 
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                  if Debugger.respond_to?(:save_history)
         | 
| 82 | 
            +
                    Debugger.save_history 
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
                
         | 
| 86 | 
            +
                def readline_support?
         | 
| 87 | 
            +
                  @have_readline
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                private
         | 
| 91 | 
            +
                begin
         | 
| 92 | 
            +
                  require 'readline'
         | 
| 93 | 
            +
                  class << Debugger
         | 
| 94 | 
            +
                    @have_readline = true
         | 
| 95 | 
            +
                    define_method(:save_history) do
         | 
| 96 | 
            +
                      iface = self.handler.interface
         | 
| 97 | 
            +
                      iface.histfile ||= File.join(ENV["HOME"]||ENV["HOMEPATH"]||".", 
         | 
| 98 | 
            +
                                              FILE_HISTORY)
         | 
| 99 | 
            +
                      open(iface.histfile, 'w') do |file|
         | 
| 100 | 
            +
                        Readline::HISTORY.to_a.last(iface.history_length).each do |line|
         | 
| 101 | 
            +
                          file.puts line unless line.strip.empty?
         | 
| 102 | 
            +
                        end if defined?(iface.history_save) and iface.history_save
         | 
| 103 | 
            +
                      end rescue nil
         | 
| 104 | 
            +
                    end
         | 
| 105 | 
            +
                    public :save_history 
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                  Debugger.debug_at_exit do 
         | 
| 108 | 
            +
                    finalize if respond_to?(:finalize)
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                  
         | 
| 111 | 
            +
                  def readline(prompt, hist)
         | 
| 112 | 
            +
                    Readline::readline(prompt, hist)
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
                rescue LoadError
         | 
| 115 | 
            +
                  def readline(prompt, hist)
         | 
| 116 | 
            +
                    @histfile = ''
         | 
| 117 | 
            +
                    @hist_save = false
         | 
| 118 | 
            +
                    STDOUT.print prompt
         | 
| 119 | 
            +
                    STDOUT.flush
         | 
| 120 | 
            +
                    line = STDIN.gets
         | 
| 121 | 
            +
                    exit unless line
         | 
| 122 | 
            +
                    line.chomp!
         | 
| 123 | 
            +
                    line
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              class RemoteInterface < Interface # :nodoc:
         | 
| 129 | 
            +
                attr_accessor :command_queue
         | 
| 130 | 
            +
                attr_accessor :histfile
         | 
| 131 | 
            +
                attr_accessor :history_save
         | 
| 132 | 
            +
                attr_accessor :history_length
         | 
| 133 | 
            +
                attr_accessor :restart_file
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                def initialize(socket)
         | 
| 136 | 
            +
                  @command_queue = []
         | 
| 137 | 
            +
                  @socket = socket
         | 
| 138 | 
            +
                  @history_save = false
         | 
| 139 | 
            +
                  @history_length = 256
         | 
| 140 | 
            +
                  @histfile = ''
         | 
| 141 | 
            +
                  # Do we read the histfile?
         | 
| 142 | 
            +
            #       open(@histfile, 'r') do |file|
         | 
| 143 | 
            +
            #         file.each do |line|
         | 
| 144 | 
            +
            #           line.chomp!
         | 
| 145 | 
            +
            #           Readline::HISTORY << line
         | 
| 146 | 
            +
            #         end
         | 
| 147 | 
            +
            #       end if File.exist?(@histfile)
         | 
| 148 | 
            +
                  @restart_file = nil
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
                
         | 
| 151 | 
            +
                def close
         | 
| 152 | 
            +
                  @socket.close
         | 
| 153 | 
            +
                rescue Exception
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
                
         | 
| 156 | 
            +
                def confirm(prompt)
         | 
| 157 | 
            +
                  send_command "CONFIRM #{prompt}"
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                def finalize
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
                
         | 
| 163 | 
            +
                def read_command(prompt)
         | 
| 164 | 
            +
                  send_command "PROMPT #{prompt}"
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
                
         | 
| 167 | 
            +
                def readline_support?
         | 
| 168 | 
            +
                  false
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                def print(*args)
         | 
| 172 | 
            +
                  @socket.printf(*args)
         | 
| 173 | 
            +
                end
         | 
| 174 | 
            +
                
         | 
| 175 | 
            +
                private
         | 
| 176 | 
            +
                
         | 
| 177 | 
            +
                def send_command(msg)
         | 
| 178 | 
            +
                  @socket.puts msg
         | 
| 179 | 
            +
                  result = @socket.gets
         | 
| 180 | 
            +
                  raise IOError unless result
         | 
| 181 | 
            +
                  result.chomp
         | 
| 182 | 
            +
                end
         | 
| 183 | 
            +
              end
         | 
| 184 | 
            +
              
         | 
| 185 | 
            +
              class ScriptInterface < Interface # :nodoc:
         | 
| 186 | 
            +
                attr_accessor :command_queue
         | 
| 187 | 
            +
                attr_accessor :histfile
         | 
| 188 | 
            +
                attr_accessor :history_save
         | 
| 189 | 
            +
                attr_accessor :history_length
         | 
| 190 | 
            +
                attr_accessor :restart_file
         | 
| 191 | 
            +
                def initialize(file, out, verbose=false)
         | 
| 192 | 
            +
                  super()
         | 
| 193 | 
            +
                  @command_queue = []
         | 
| 194 | 
            +
                  @file = file.respond_to?(:gets) ? file : open(file)
         | 
| 195 | 
            +
                  @out = out
         | 
| 196 | 
            +
                  @verbose = verbose
         | 
| 197 | 
            +
                  @history_save = false
         | 
| 198 | 
            +
                  @history_length = 256  # take gdb default
         | 
| 199 | 
            +
                  @histfile = ''
         | 
| 200 | 
            +
                end
         | 
| 201 | 
            +
                
         | 
| 202 | 
            +
                def finalize
         | 
| 203 | 
            +
                end
         | 
| 204 | 
            +
                
         | 
| 205 | 
            +
                def read_command(prompt)
         | 
| 206 | 
            +
                  while result = @file.gets
         | 
| 207 | 
            +
                    puts "# #{result}" if @verbose
         | 
| 208 | 
            +
                    next if result =~ /^\s*#/
         | 
| 209 | 
            +
                    next if result.strip.empty?
         | 
| 210 | 
            +
                    break
         | 
| 211 | 
            +
                  end
         | 
| 212 | 
            +
                  raise IOError unless result
         | 
| 213 | 
            +
                  result.chomp!
         | 
| 214 | 
            +
                end
         | 
| 215 | 
            +
                
         | 
| 216 | 
            +
                def readline_support?
         | 
| 217 | 
            +
                  false
         | 
| 218 | 
            +
                end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                def confirm(prompt)
         | 
| 221 | 
            +
                  'y'
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
                
         | 
| 224 | 
            +
                def print(*args)
         | 
| 225 | 
            +
                  @out.printf(*args)
         | 
| 226 | 
            +
                end
         | 
| 227 | 
            +
                
         | 
| 228 | 
            +
                def close
         | 
| 229 | 
            +
                  @file.close
         | 
| 230 | 
            +
                end
         | 
| 231 | 
            +
              end
         | 
| 232 | 
            +
            end
         | 
| @@ -0,0 +1,474 @@ | |
| 1 | 
            +
            require_relative 'interface'
         | 
| 2 | 
            +
            require_relative 'command'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Debugger
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              # Should this be a mixin?
         | 
| 7 | 
            +
              class Processor # :nodoc
         | 
| 8 | 
            +
                attr_accessor :interface
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                # Format msg with gdb-style annotation header
         | 
| 11 | 
            +
                def afmt(msg, newline="\n")
         | 
| 12 | 
            +
                  "\032\032#{msg}#{newline}"
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                def aprint(msg)
         | 
| 16 | 
            +
                  print afmt(msg) if Debugger.annotate.to_i > 2
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # FIXME: use delegate? 
         | 
| 20 | 
            +
                def errmsg(*args)
         | 
| 21 | 
            +
                  @interface.errmsg(*args)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                # Callers of this routine should make sure to use comma to
         | 
| 25 | 
            +
                # separate format argments rather than %. Otherwise it seems that
         | 
| 26 | 
            +
                # if the string you want to print has format specifier, which
         | 
| 27 | 
            +
                # could happen if you are trying to show say a source-code line
         | 
| 28 | 
            +
                # with "puts" or "print" in it, this print routine will give an
         | 
| 29 | 
            +
                # error saying it is looking for more arguments.
         | 
| 30 | 
            +
                def print(*args)
         | 
| 31 | 
            +
                  @interface.print(*args)
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              class CommandProcessor < Processor # :nodoc:
         | 
| 37 | 
            +
                attr_reader   :display
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                # FIXME: get from Command regexp method.
         | 
| 40 | 
            +
                @@Show_breakpoints_postcmd = [
         | 
| 41 | 
            +
                                              /^\s*b(?:reak)?/, 
         | 
| 42 | 
            +
                                              /^\s* cond(?:ition)? (?:\s+(\d+)\s*(.*))?$/ix,
         | 
| 43 | 
            +
                                              /^\s*del(?:ete)?(?:\s+(.*))?$/ix,
         | 
| 44 | 
            +
                                              /^\s* dis(?:able)? (?:\s+(.*))?$/ix,
         | 
| 45 | 
            +
                                              /^\s* en(?:able)? (?:\s+(.*))?$/ix,
         | 
| 46 | 
            +
                                              # "tbreak", "clear", 
         | 
| 47 | 
            +
                                             ]
         | 
| 48 | 
            +
                @@Show_annotations_run     = [
         | 
| 49 | 
            +
                                              /^\s*c(?:ont(?:inue)?)?(?:\s+(.*))?$/,
         | 
| 50 | 
            +
                                              /^\s*fin(?:ish)?$/,
         | 
| 51 | 
            +
                                              /^\s*n(?:ext)?([+-])?(?:\s+(.*))?$/,
         | 
| 52 | 
            +
                                              /^\s*s(?:tep)?([+-])?(?:\s+(.*))?$/
         | 
| 53 | 
            +
                                            ]
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                @@Show_annotations_postcmd = [
         | 
| 56 | 
            +
                                              /^\s* down (?:\s+(.*))? .*$/x,
         | 
| 57 | 
            +
                                              /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x,
         | 
| 58 | 
            +
                                              /^\s* u(?:p)? (?:\s+(.*))?$/x
         | 
| 59 | 
            +
                                             ]
         | 
| 60 | 
            +
                
         | 
| 61 | 
            +
                def initialize(interface = LocalInterface.new)
         | 
| 62 | 
            +
                  @interface = interface
         | 
| 63 | 
            +
                  @display = []
         | 
| 64 | 
            +
                  
         | 
| 65 | 
            +
                  @mutex = Mutex.new
         | 
| 66 | 
            +
                  @last_cmd = nil
         | 
| 67 | 
            +
                  @last_file = nil   # Filename the last time we stopped
         | 
| 68 | 
            +
                  @last_line = nil   # line number the last time we stopped
         | 
| 69 | 
            +
                  @debugger_breakpoints_were_empty = false # Show breakpoints 1st time
         | 
| 70 | 
            +
                  @debugger_displays_were_empty = true # No display 1st time
         | 
| 71 | 
            +
                  @debugger_context_was_dead = true # Assume we haven't started.
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
                
         | 
| 74 | 
            +
                def interface=(interface)
         | 
| 75 | 
            +
                  @mutex.synchronize do
         | 
| 76 | 
            +
                    @interface.close if @interface
         | 
| 77 | 
            +
                    @interface = interface
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                require 'pathname'  # For cleanpath
         | 
| 82 | 
            +
                
         | 
| 83 | 
            +
                # Regularize file name. 
         | 
| 84 | 
            +
                # This is also used as a common funnel place if basename is 
         | 
| 85 | 
            +
                # desired or if we are working remotely and want to change the 
         | 
| 86 | 
            +
                # basename. Or we are eliding filenames.
         | 
| 87 | 
            +
                def self.canonic_file(filename)
         | 
| 88 | 
            +
                  # For now we want resolved filenames 
         | 
| 89 | 
            +
                  if Command.settings[:basename]
         | 
| 90 | 
            +
                    File.basename(filename)
         | 
| 91 | 
            +
                  else
         | 
| 92 | 
            +
                    # Cache this?
         | 
| 93 | 
            +
                    Pathname.new(filename).cleanpath.to_s
         | 
| 94 | 
            +
                  end
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def self.print_location_and_text(file, line)
         | 
| 98 | 
            +
                  file_line = "%s:%s\n%s" % [canonic_file(file), line, 
         | 
| 99 | 
            +
                                             Debugger.line_at(file, line)]
         | 
| 100 | 
            +
                  # FIXME: use annotations routines
         | 
| 101 | 
            +
                  if Debugger.annotate.to_i > 2
         | 
| 102 | 
            +
                    file_line = "\032\032source #{file_line}"
         | 
| 103 | 
            +
                  elsif ENV['EMACS']
         | 
| 104 | 
            +
                    file_line = "\032\032#{file_line}"
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                  print file_line
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
              
         | 
| 109 | 
            +
                def self.protect(mname)
         | 
| 110 | 
            +
                  alias_method "__#{mname}", mname
         | 
| 111 | 
            +
                  module_eval %{
         | 
| 112 | 
            +
                    def #{mname}(*args)
         | 
| 113 | 
            +
                      @mutex.synchronize do
         | 
| 114 | 
            +
                        return unless @interface
         | 
| 115 | 
            +
                        __#{mname}(*args)
         | 
| 116 | 
            +
                      end
         | 
| 117 | 
            +
                    rescue IOError, Errno::EPIPE
         | 
| 118 | 
            +
                      self.interface = nil
         | 
| 119 | 
            +
                    rescue SignalException
         | 
| 120 | 
            +
                      raise
         | 
| 121 | 
            +
                    rescue Exception
         | 
| 122 | 
            +
                      print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
         | 
| 123 | 
            +
                      print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
         | 
| 124 | 
            +
                    end
         | 
| 125 | 
            +
                  }
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
                
         | 
| 128 | 
            +
                def at_breakpoint(context, breakpoint)
         | 
| 129 | 
            +
                  aprint 'stopped' if Debugger.annotate.to_i > 2
         | 
| 130 | 
            +
                  n = Debugger.breakpoints.index(breakpoint) + 1
         | 
| 131 | 
            +
                  file = CommandProcessor.canonic_file(breakpoint.source)
         | 
| 132 | 
            +
                  line = breakpoint.pos
         | 
| 133 | 
            +
                  if Debugger.annotate.to_i > 2
         | 
| 134 | 
            +
                    print afmt("source #{file}:#{line}")
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
                  print "Breakpoint %d at %s:%s\n", n, file, line
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
                protect :at_breakpoint
         | 
| 139 | 
            +
                
         | 
| 140 | 
            +
                def at_catchpoint(context, excpt)
         | 
| 141 | 
            +
                  aprint 'stopped' if Debugger.annotate.to_i > 2
         | 
| 142 | 
            +
                  file = CommandProcessor.canonic_file(context.frame_file(0))
         | 
| 143 | 
            +
                  line = context.frame_line(0)
         | 
| 144 | 
            +
                  print afmt("%s:%d" % [file, line]) if ENV['EMACS']
         | 
| 145 | 
            +
                  print "Catchpoint at %s:%d: `%s' (%s)\n", file, line, excpt, excpt.class
         | 
| 146 | 
            +
                  fs = context.stack_size
         | 
| 147 | 
            +
                  tb = caller(0)[-fs..-1]
         | 
| 148 | 
            +
                  if tb
         | 
| 149 | 
            +
                    for i in tb
         | 
| 150 | 
            +
                      print "\tfrom %s\n", i
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
                protect :at_catchpoint
         | 
| 155 | 
            +
                
         | 
| 156 | 
            +
                def at_tracing(context, file, line)
         | 
| 157 | 
            +
                  return if defined?(Debugger::RDEBUG_FILE) && 
         | 
| 158 | 
            +
                    Debugger::RDEBUG_FILE == file # Don't trace ourself
         | 
| 159 | 
            +
                  @last_file = CommandProcessor.canonic_file(file)
         | 
| 160 | 
            +
                  file = CommandProcessor.canonic_file(file)
         | 
| 161 | 
            +
                  unless file == @last_file and @last_line == line and 
         | 
| 162 | 
            +
                      Command.settings[:tracing_plus]
         | 
| 163 | 
            +
                    print "Tracing(%d):%s:%s %s",
         | 
| 164 | 
            +
                    context.thnum, file, line, Debugger.line_at(file, line)
         | 
| 165 | 
            +
                    @last_file = file
         | 
| 166 | 
            +
                    @last_line = line
         | 
| 167 | 
            +
                  end
         | 
| 168 | 
            +
                  always_run(context, file, line, 2)
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
                protect :at_tracing
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                def at_line(context, file, line)
         | 
| 173 | 
            +
                  process_commands(context, file, line)
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
                protect :at_line
         | 
| 176 | 
            +
                
         | 
| 177 | 
            +
                def at_return(context, file, line)
         | 
| 178 | 
            +
                  context.stop_frame = -1
         | 
| 179 | 
            +
                  process_commands(context, file, line)
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
                
         | 
| 182 | 
            +
                private
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                # The prompt shown before reading a command.
         | 
| 185 | 
            +
                def prompt(context)
         | 
| 186 | 
            +
                  p = '(rdb:%s) ' % (context.dead?  ? 'post-mortem' : context.thnum)
         | 
| 187 | 
            +
                  p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if 
         | 
| 188 | 
            +
                    Debugger.annotate.to_i > 2
         | 
| 189 | 
            +
                  return p
         | 
| 190 | 
            +
                end
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                # Run these commands, for example display commands or possibly
         | 
| 193 | 
            +
                # the list or irb in an "autolist" or "autoirb".
         | 
| 194 | 
            +
                # We return a list of commands that are acceptable to run bound
         | 
| 195 | 
            +
                # to the current state.
         | 
| 196 | 
            +
                def always_run(context, file, line, run_level)
         | 
| 197 | 
            +
                  event_cmds = Command.commands.select{|cmd| cmd.event }
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                  # Remove some commands in post-mortem
         | 
| 200 | 
            +
                  event_cmds = event_cmds.find_all do |cmd| 
         | 
| 201 | 
            +
                    cmd.allow_in_post_mortem
         | 
| 202 | 
            +
                  end if context.dead?
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  state = State.new do |s|
         | 
| 205 | 
            +
                    s.context = context
         | 
| 206 | 
            +
                    s.file    = file
         | 
| 207 | 
            +
                    s.line    = line
         | 
| 208 | 
            +
                    s.binding = context.frame_binding(0)
         | 
| 209 | 
            +
                    s.display = display
         | 
| 210 | 
            +
                    s.interface = interface
         | 
| 211 | 
            +
                    s.commands = event_cmds
         | 
| 212 | 
            +
                  end
         | 
| 213 | 
            +
                  @interface.state = state if @interface.respond_to?('state=')
         | 
| 214 | 
            +
                  
         | 
| 215 | 
            +
                  # Bind commands to the current state.
         | 
| 216 | 
            +
                  commands = event_cmds.map{|cmd| cmd.new(state)}
         | 
| 217 | 
            +
             | 
| 218 | 
            +
                  commands.select do |cmd| 
         | 
| 219 | 
            +
                    cmd.class.always_run >= run_level
         | 
| 220 | 
            +
                  end.each {|cmd| cmd.execute}
         | 
| 221 | 
            +
                  return state, commands
         | 
| 222 | 
            +
                end
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                # Handle debugger commands
         | 
| 225 | 
            +
                def process_commands(context, file, line)
         | 
| 226 | 
            +
                  state, commands = always_run(context, file, line, 1)
         | 
| 227 | 
            +
                  $rdebug_state = state if Command.settings[:debuggertesting]
         | 
| 228 | 
            +
                  splitter = lambda do |str|
         | 
| 229 | 
            +
                    str.split(/;/).inject([]) do |m, v|
         | 
| 230 | 
            +
                      if m.empty?
         | 
| 231 | 
            +
                        m << v
         | 
| 232 | 
            +
                      else
         | 
| 233 | 
            +
                        if m.last[-1] == ?\\
         | 
| 234 | 
            +
                          m.last[-1,1] = ''
         | 
| 235 | 
            +
                          m.last << ';' << v
         | 
| 236 | 
            +
                        else
         | 
| 237 | 
            +
                          m << v
         | 
| 238 | 
            +
                        end
         | 
| 239 | 
            +
                      end
         | 
| 240 | 
            +
                      m
         | 
| 241 | 
            +
                    end
         | 
| 242 | 
            +
                  end
         | 
| 243 | 
            +
                  
         | 
| 244 | 
            +
                  preloop(commands, context)
         | 
| 245 | 
            +
                  CommandProcessor.print_location_and_text(file, line)
         | 
| 246 | 
            +
                  while !state.proceed? 
         | 
| 247 | 
            +
                    input = if @interface.command_queue.empty?
         | 
| 248 | 
            +
                              @interface.read_command(prompt(context))
         | 
| 249 | 
            +
                            else
         | 
| 250 | 
            +
                              @interface.command_queue.shift
         | 
| 251 | 
            +
                            end
         | 
| 252 | 
            +
                    break unless input
         | 
| 253 | 
            +
                    catch(:debug_error) do
         | 
| 254 | 
            +
                      if input == ""
         | 
| 255 | 
            +
                        next unless @last_cmd
         | 
| 256 | 
            +
                        input = @last_cmd
         | 
| 257 | 
            +
                      else
         | 
| 258 | 
            +
                        @last_cmd = input
         | 
| 259 | 
            +
                      end
         | 
| 260 | 
            +
                      splitter[input].each do |cmd|
         | 
| 261 | 
            +
                        one_cmd(commands, context, cmd)
         | 
| 262 | 
            +
                        postcmd(commands, context, cmd)
         | 
| 263 | 
            +
                      end
         | 
| 264 | 
            +
                    end
         | 
| 265 | 
            +
                  end
         | 
| 266 | 
            +
                  postloop(commands, context)
         | 
| 267 | 
            +
                end # process_commands
         | 
| 268 | 
            +
                
         | 
| 269 | 
            +
                def one_cmd(commands, context, input)
         | 
| 270 | 
            +
                  if cmd = commands.find{ |c| c.match(input) }
         | 
| 271 | 
            +
                    if context.dead? && cmd.class.need_context
         | 
| 272 | 
            +
                      p cmd
         | 
| 273 | 
            +
                      print "Command is unavailable\n"
         | 
| 274 | 
            +
                    else
         | 
| 275 | 
            +
                      cmd.execute
         | 
| 276 | 
            +
                    end
         | 
| 277 | 
            +
                  else
         | 
| 278 | 
            +
                    unknown_cmd = commands.find{|cmd| cmd.class.unknown }
         | 
| 279 | 
            +
                    if unknown_cmd
         | 
| 280 | 
            +
                        unknown_cmd.execute
         | 
| 281 | 
            +
                    else
         | 
| 282 | 
            +
                      errmsg "Unknown command: \"#{input}\".  Try \"help\".\n"
         | 
| 283 | 
            +
                    end
         | 
| 284 | 
            +
                  end
         | 
| 285 | 
            +
                end
         | 
| 286 | 
            +
                
         | 
| 287 | 
            +
                def preloop(commands, context)
         | 
| 288 | 
            +
                  aprint('stopped') if Debugger.annotate.to_i > 2
         | 
| 289 | 
            +
                  if context.dead?
         | 
| 290 | 
            +
                    unless @debugger_context_was_dead
         | 
| 291 | 
            +
                      if Debugger.annotate.to_i > 2
         | 
| 292 | 
            +
                        aprint('exited') 
         | 
| 293 | 
            +
                        print "The program finished.\n" 
         | 
| 294 | 
            +
                      end
         | 
| 295 | 
            +
                      @debugger_context_was_dead = true
         | 
| 296 | 
            +
                    end
         | 
| 297 | 
            +
                  end
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                  if Debugger.annotate.to_i > 2
         | 
| 300 | 
            +
                    # if we are here, the stack frames have changed outside the
         | 
| 301 | 
            +
                    # command loop (e.g. after a "continue" command), so we show
         | 
| 302 | 
            +
                    # the annotations again
         | 
| 303 | 
            +
                    breakpoint_annotations(commands, context)
         | 
| 304 | 
            +
                    display_annotations(commands, context)
         | 
| 305 | 
            +
                    annotation('stack', commands, context, "where")
         | 
| 306 | 
            +
                    annotation('variables', commands, context, "info variables") unless
         | 
| 307 | 
            +
                      context.dead?
         | 
| 308 | 
            +
                  end
         | 
| 309 | 
            +
                end
         | 
| 310 | 
            +
                
         | 
| 311 | 
            +
                def postcmd(commands, context, cmd)
         | 
| 312 | 
            +
                  if Debugger.annotate.to_i > 0
         | 
| 313 | 
            +
                    cmd = @last_cmd unless cmd
         | 
| 314 | 
            +
                    breakpoint_annotations(commands, context) if
         | 
| 315 | 
            +
                      @@Show_breakpoints_postcmd.find{|pat| cmd =~ pat}
         | 
| 316 | 
            +
                    display_annotations(commands, context)
         | 
| 317 | 
            +
                    if @@Show_annotations_postcmd.find{|pat| cmd =~ pat}
         | 
| 318 | 
            +
                      annotation('stack', commands, context, "where") if 
         | 
| 319 | 
            +
                        context.stack_size > 0
         | 
| 320 | 
            +
                      annotation('variables', commands, context, "info variables") unless
         | 
| 321 | 
            +
                        context.dead?
         | 
| 322 | 
            +
                    end
         | 
| 323 | 
            +
                    if not context.dead? and @@Show_annotations_run.find{|pat| cmd =~ pat}
         | 
| 324 | 
            +
                      aprint 'starting'  if Debugger.annotate.to_i > 2
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                      @debugger_context_was_dead = false
         | 
| 327 | 
            +
                    end
         | 
| 328 | 
            +
                  end
         | 
| 329 | 
            +
                end
         | 
| 330 | 
            +
             | 
| 331 | 
            +
                def postloop(commands, context)
         | 
| 332 | 
            +
                end
         | 
| 333 | 
            +
             | 
| 334 | 
            +
                def annotation(label, commands, context, cmd)
         | 
| 335 | 
            +
                  print afmt(label)
         | 
| 336 | 
            +
                  one_cmd(commands, context, cmd)
         | 
| 337 | 
            +
                  ### FIXME ANNOTATE: the following line should be deleted
         | 
| 338 | 
            +
                  print "\032\032\n"
         | 
| 339 | 
            +
                end
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                def breakpoint_annotations(commands, context)
         | 
| 342 | 
            +
                  unless Debugger.breakpoints.empty? and @debugger_breakpoints_were_empty
         | 
| 343 | 
            +
                    annotation('breakpoints', commands, context, "info breakpoints") 
         | 
| 344 | 
            +
                    @debugger_breakpoints_were_empty = Debugger.breakpoints.empty?
         | 
| 345 | 
            +
                  end
         | 
| 346 | 
            +
                end
         | 
| 347 | 
            +
             | 
| 348 | 
            +
                def display_annotations(commands, context)
         | 
| 349 | 
            +
                  return if display.empty?
         | 
| 350 | 
            +
            #       have_display = display.find{|d| d[0]} 
         | 
| 351 | 
            +
            #       return unless have_display and @debugger_displays_were_empty
         | 
| 352 | 
            +
            #       @debugger_displays_were_empty = have_display
         | 
| 353 | 
            +
                  annotation('display', commands, context, "display")
         | 
| 354 | 
            +
                end
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                class State # :nodoc:
         | 
| 357 | 
            +
                  attr_accessor :context, :file, :line, :binding
         | 
| 358 | 
            +
                  attr_accessor :frame_pos, :previous_line, :display
         | 
| 359 | 
            +
                  attr_accessor :interface, :commands
         | 
| 360 | 
            +
             | 
| 361 | 
            +
                  def initialize
         | 
| 362 | 
            +
                    super()
         | 
| 363 | 
            +
                    @frame_pos = 0
         | 
| 364 | 
            +
                    @previous_line = nil
         | 
| 365 | 
            +
                    @proceed = false
         | 
| 366 | 
            +
                    yield self
         | 
| 367 | 
            +
                  end
         | 
| 368 | 
            +
             | 
| 369 | 
            +
                  # FIXME: use delegate? 
         | 
| 370 | 
            +
                  def errmsg(*args)
         | 
| 371 | 
            +
                    @interface.errmsg(*args)
         | 
| 372 | 
            +
                  end
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                  def print(*args)
         | 
| 375 | 
            +
                    @interface.print(*args)
         | 
| 376 | 
            +
                  end
         | 
| 377 | 
            +
             | 
| 378 | 
            +
                  def confirm(*args)
         | 
| 379 | 
            +
                    @interface.confirm(*args)
         | 
| 380 | 
            +
                  end
         | 
| 381 | 
            +
             | 
| 382 | 
            +
                  def proceed?
         | 
| 383 | 
            +
                    @proceed
         | 
| 384 | 
            +
                  end
         | 
| 385 | 
            +
             | 
| 386 | 
            +
                  def proceed
         | 
| 387 | 
            +
                    @proceed = true
         | 
| 388 | 
            +
                  end
         | 
| 389 | 
            +
                end
         | 
| 390 | 
            +
              end
         | 
| 391 | 
            +
              
         | 
| 392 | 
            +
              class ControlCommandProcessor < Processor # :nodoc:
         | 
| 393 | 
            +
                def initialize(interface)
         | 
| 394 | 
            +
                  super()
         | 
| 395 | 
            +
                  @interface = interface
         | 
| 396 | 
            +
                  @debugger_context_was_dead = true # Assume we haven't started.
         | 
| 397 | 
            +
                end
         | 
| 398 | 
            +
                
         | 
| 399 | 
            +
                def process_commands(verbose=false)
         | 
| 400 | 
            +
                  control_cmds = Command.commands.select do |cmd| 
         | 
| 401 | 
            +
                    cmd.allow_in_control 
         | 
| 402 | 
            +
                  end
         | 
| 403 | 
            +
                  state = State.new(@interface, control_cmds)
         | 
| 404 | 
            +
                  commands = control_cmds.map{|cmd| cmd.new(state) }
         | 
| 405 | 
            +
             | 
| 406 | 
            +
                  unless @debugger_context_was_dead
         | 
| 407 | 
            +
                    if Debugger.annotate.to_i > 2
         | 
| 408 | 
            +
                      aprint 'exited'  
         | 
| 409 | 
            +
                      print "The program finished.\n" 
         | 
| 410 | 
            +
                    end
         | 
| 411 | 
            +
                    @debugger_context_was_dead = true
         | 
| 412 | 
            +
                  end
         | 
| 413 | 
            +
             | 
| 414 | 
            +
                  while input = @interface.read_command(prompt(nil))
         | 
| 415 | 
            +
                    print "+#{input}" if verbose
         | 
| 416 | 
            +
                    catch(:debug_error) do
         | 
| 417 | 
            +
                      if cmd = commands.find{|c| c.match(input) }
         | 
| 418 | 
            +
                        cmd.execute
         | 
| 419 | 
            +
                      else
         | 
| 420 | 
            +
                        errmsg "Unknown command\n"
         | 
| 421 | 
            +
                      end
         | 
| 422 | 
            +
                    end
         | 
| 423 | 
            +
                  end
         | 
| 424 | 
            +
                rescue IOError, Errno::EPIPE
         | 
| 425 | 
            +
                rescue Exception
         | 
| 426 | 
            +
                  print "INTERNAL ERROR!!! #{$!}\n" rescue nil
         | 
| 427 | 
            +
                  print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
         | 
| 428 | 
            +
                ensure
         | 
| 429 | 
            +
                  @interface.close
         | 
| 430 | 
            +
                end
         | 
| 431 | 
            +
             | 
| 432 | 
            +
                # The prompt shown before reading a command.
         | 
| 433 | 
            +
                # Note: have an unused 'context' parameter to match the local interface.
         | 
| 434 | 
            +
                def prompt(context)
         | 
| 435 | 
            +
                  p = '(rdb:ctrl) '
         | 
| 436 | 
            +
                  p = afmt("pre-prompt")+p+"\n"+afmt("prompt") if 
         | 
| 437 | 
            +
                    Debugger.annotate.to_i > 2
         | 
| 438 | 
            +
                  return p
         | 
| 439 | 
            +
                end
         | 
| 440 | 
            +
             | 
| 441 | 
            +
                class State # :nodoc:
         | 
| 442 | 
            +
                  attr_reader :commands, :interface
         | 
| 443 | 
            +
                  
         | 
| 444 | 
            +
                  def initialize(interface, commands)
         | 
| 445 | 
            +
                    @interface = interface
         | 
| 446 | 
            +
                    @commands = commands
         | 
| 447 | 
            +
                  end
         | 
| 448 | 
            +
                  
         | 
| 449 | 
            +
                  def proceed
         | 
| 450 | 
            +
                  end
         | 
| 451 | 
            +
                  
         | 
| 452 | 
            +
                  def errmsg(*args)
         | 
| 453 | 
            +
                    @interface.print(*args)
         | 
| 454 | 
            +
                  end
         | 
| 455 | 
            +
                  
         | 
| 456 | 
            +
                  def print(*args)
         | 
| 457 | 
            +
                    @interface.print(*args)
         | 
| 458 | 
            +
                  end
         | 
| 459 | 
            +
                  
         | 
| 460 | 
            +
                  def confirm(*args)
         | 
| 461 | 
            +
                    'y'
         | 
| 462 | 
            +
                  end
         | 
| 463 | 
            +
                  
         | 
| 464 | 
            +
                  def context
         | 
| 465 | 
            +
                    nil
         | 
| 466 | 
            +
                  end
         | 
| 467 | 
            +
             | 
| 468 | 
            +
                  def file
         | 
| 469 | 
            +
                    errmsg "No filename given.\n"
         | 
| 470 | 
            +
                    throw :debug_error
         | 
| 471 | 
            +
                  end
         | 
| 472 | 
            +
                end # State
         | 
| 473 | 
            +
              end
         | 
| 474 | 
            +
            end
         |