needy_debugger 1.4.0

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.
Files changed (187) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +8 -0
  3. data/AUTHORS +10 -0
  4. data/CHANGELOG.md +68 -0
  5. data/CONTRIBUTING.md +1 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +23 -0
  8. data/OLDER_CHANGELOG +334 -0
  9. data/OLD_CHANGELOG +5655 -0
  10. data/OLD_README +122 -0
  11. data/README.md +141 -0
  12. data/Rakefile +78 -0
  13. data/bin/rdebug +397 -0
  14. data/doc/.cvsignore +42 -0
  15. data/doc/Makefile.am +63 -0
  16. data/doc/emacs-notes.txt +38 -0
  17. data/doc/hanoi.rb +35 -0
  18. data/doc/primes.rb +28 -0
  19. data/doc/rdebug-emacs.texi +1030 -0
  20. data/doc/ruby-debug.texi +3791 -0
  21. data/doc/test-tri2.rb +18 -0
  22. data/doc/tri3.rb +8 -0
  23. data/doc/triangle.rb +12 -0
  24. data/emacs/Makefile.am +130 -0
  25. data/emacs/rdebug-annotate.el +385 -0
  26. data/emacs/rdebug-breaks.el +407 -0
  27. data/emacs/rdebug-cmd.el +92 -0
  28. data/emacs/rdebug-core.el +502 -0
  29. data/emacs/rdebug-dbg.el +62 -0
  30. data/emacs/rdebug-error.el +79 -0
  31. data/emacs/rdebug-fns.el +111 -0
  32. data/emacs/rdebug-frames.el +230 -0
  33. data/emacs/rdebug-gud.el +242 -0
  34. data/emacs/rdebug-help.el +104 -0
  35. data/emacs/rdebug-info.el +83 -0
  36. data/emacs/rdebug-layouts.el +180 -0
  37. data/emacs/rdebug-locring.el +118 -0
  38. data/emacs/rdebug-output.el +106 -0
  39. data/emacs/rdebug-regexp.el +118 -0
  40. data/emacs/rdebug-secondary.el +260 -0
  41. data/emacs/rdebug-shortkey.el +175 -0
  42. data/emacs/rdebug-source.el +568 -0
  43. data/emacs/rdebug-track.el +392 -0
  44. data/emacs/rdebug-varbuf.el +150 -0
  45. data/emacs/rdebug-vars.el +125 -0
  46. data/emacs/rdebug-watch.el +132 -0
  47. data/emacs/rdebug.el +326 -0
  48. data/emacs/test/elk-test.el +242 -0
  49. data/emacs/test/test-annotate.el +103 -0
  50. data/emacs/test/test-cmd.el +116 -0
  51. data/emacs/test/test-core.el +104 -0
  52. data/emacs/test/test-fns.el +65 -0
  53. data/emacs/test/test-frames.el +62 -0
  54. data/emacs/test/test-gud.el +35 -0
  55. data/emacs/test/test-indent.el +58 -0
  56. data/emacs/test/test-regexp.el +144 -0
  57. data/emacs/test/test-shortkey.el +61 -0
  58. data/ext/ruby_debug/192/breakpoint.c +586 -0
  59. data/ext/ruby_debug/192/ruby_debug.c +2645 -0
  60. data/ext/ruby_debug/192/ruby_debug.h +148 -0
  61. data/ext/ruby_debug/193/breakpoint.c +586 -0
  62. data/ext/ruby_debug/193/ruby_debug.c +2626 -0
  63. data/ext/ruby_debug/193/ruby_debug.h +148 -0
  64. data/ext/ruby_debug/200/breakpoint.c +586 -0
  65. data/ext/ruby_debug/200/ruby_debug.c +2692 -0
  66. data/ext/ruby_debug/200/ruby_debug.h +148 -0
  67. data/ext/ruby_debug/extconf.rb +94 -0
  68. data/lib/debugger.rb +5 -0
  69. data/lib/debugger/version.rb +5 -0
  70. data/lib/ruby-debug-base.rb +305 -0
  71. data/lib/ruby-debug.rb +177 -0
  72. data/lib/ruby-debug/command.rb +227 -0
  73. data/lib/ruby-debug/commands/breakpoints.rb +153 -0
  74. data/lib/ruby-debug/commands/catchpoint.rb +55 -0
  75. data/lib/ruby-debug/commands/condition.rb +49 -0
  76. data/lib/ruby-debug/commands/continue.rb +38 -0
  77. data/lib/ruby-debug/commands/control.rb +107 -0
  78. data/lib/ruby-debug/commands/display.rb +120 -0
  79. data/lib/ruby-debug/commands/edit.rb +48 -0
  80. data/lib/ruby-debug/commands/enable.rb +202 -0
  81. data/lib/ruby-debug/commands/eval.rb +176 -0
  82. data/lib/ruby-debug/commands/finish.rb +42 -0
  83. data/lib/ruby-debug/commands/frame.rb +301 -0
  84. data/lib/ruby-debug/commands/help.rb +56 -0
  85. data/lib/ruby-debug/commands/info.rb +467 -0
  86. data/lib/ruby-debug/commands/irb.rb +123 -0
  87. data/lib/ruby-debug/commands/jump.rb +66 -0
  88. data/lib/ruby-debug/commands/kill.rb +51 -0
  89. data/lib/ruby-debug/commands/list.rb +94 -0
  90. data/lib/ruby-debug/commands/method.rb +84 -0
  91. data/lib/ruby-debug/commands/quit.rb +50 -0
  92. data/lib/ruby-debug/commands/reload.rb +40 -0
  93. data/lib/ruby-debug/commands/save.rb +90 -0
  94. data/lib/ruby-debug/commands/set.rb +223 -0
  95. data/lib/ruby-debug/commands/show.rb +247 -0
  96. data/lib/ruby-debug/commands/skip.rb +35 -0
  97. data/lib/ruby-debug/commands/source.rb +36 -0
  98. data/lib/ruby-debug/commands/stepping.rb +81 -0
  99. data/lib/ruby-debug/commands/threads.rb +189 -0
  100. data/lib/ruby-debug/commands/tmate.rb +36 -0
  101. data/lib/ruby-debug/commands/trace.rb +57 -0
  102. data/lib/ruby-debug/commands/variables.rb +199 -0
  103. data/lib/ruby-debug/debugger.rb +5 -0
  104. data/lib/ruby-debug/helper.rb +69 -0
  105. data/lib/ruby-debug/interface.rb +232 -0
  106. data/lib/ruby-debug/processor.rb +474 -0
  107. data/man/rdebug.1 +241 -0
  108. data/needy_debugger.gemspec +31 -0
  109. data/old_scripts/Makefile.am +14 -0
  110. data/old_scripts/README.md +2 -0
  111. data/old_scripts/autogen.sh +4 -0
  112. data/old_scripts/configure.ac +12 -0
  113. data/old_scripts/rdbg.rb +33 -0
  114. data/old_scripts/runner.sh +7 -0
  115. data/old_scripts/svn2cl_usermap +3 -0
  116. data/test/.cvsignore +1 -0
  117. data/test/breakpoints_test.rb +365 -0
  118. data/test/conditions_test.rb +76 -0
  119. data/test/continue_test.rb +28 -0
  120. data/test/display_test.rb +141 -0
  121. data/test/edit_test.rb +55 -0
  122. data/test/eval_test.rb +92 -0
  123. data/test/examples/breakpoint1.rb +15 -0
  124. data/test/examples/breakpoint2.rb +7 -0
  125. data/test/examples/conditions.rb +4 -0
  126. data/test/examples/continue.rb +4 -0
  127. data/test/examples/display.rb +5 -0
  128. data/test/examples/edit.rb +3 -0
  129. data/test/examples/edit2.rb +3 -0
  130. data/test/examples/eval.rb +4 -0
  131. data/test/examples/finish.rb +20 -0
  132. data/test/examples/frame.rb +31 -0
  133. data/test/examples/help.rb +2 -0
  134. data/test/examples/info.rb +48 -0
  135. data/test/examples/info2.rb +3 -0
  136. data/test/examples/irb.rb +6 -0
  137. data/test/examples/jump.rb +14 -0
  138. data/test/examples/kill.rb +2 -0
  139. data/test/examples/list.rb +12 -0
  140. data/test/examples/method.rb +15 -0
  141. data/test/examples/post_mortem.rb +19 -0
  142. data/test/examples/quit.rb +2 -0
  143. data/test/examples/reload.rb +6 -0
  144. data/test/examples/restart.rb +6 -0
  145. data/test/examples/save.rb +3 -0
  146. data/test/examples/set.rb +3 -0
  147. data/test/examples/set_annotate.rb +12 -0
  148. data/test/examples/settings.rb +1 -0
  149. data/test/examples/show.rb +2 -0
  150. data/test/examples/source.rb +3 -0
  151. data/test/examples/stepping.rb +21 -0
  152. data/test/examples/thread.rb +32 -0
  153. data/test/examples/tmate.rb +10 -0
  154. data/test/examples/trace.rb +7 -0
  155. data/test/examples/trace_threads.rb +20 -0
  156. data/test/examples/variables.rb +26 -0
  157. data/test/finish_test.rb +48 -0
  158. data/test/frame_test.rb +140 -0
  159. data/test/help_test.rb +50 -0
  160. data/test/info_test.rb +325 -0
  161. data/test/irb_test.rb +81 -0
  162. data/test/jump_test.rb +70 -0
  163. data/test/kill_test.rb +47 -0
  164. data/test/list_test.rb +145 -0
  165. data/test/method_test.rb +70 -0
  166. data/test/post_mortem_test.rb +25 -0
  167. data/test/quit_test.rb +55 -0
  168. data/test/reload_test.rb +43 -0
  169. data/test/restart_test.rb +143 -0
  170. data/test/save_test.rb +92 -0
  171. data/test/set_test.rb +177 -0
  172. data/test/show_test.rb +292 -0
  173. data/test/source_test.rb +44 -0
  174. data/test/stepping_test.rb +118 -0
  175. data/test/support/breakpoint.rb +12 -0
  176. data/test/support/context.rb +14 -0
  177. data/test/support/matchers.rb +67 -0
  178. data/test/support/mocha_extensions.rb +71 -0
  179. data/test/support/processor.rb +7 -0
  180. data/test/support/test_dsl.rb +205 -0
  181. data/test/support/test_interface.rb +66 -0
  182. data/test/test_helper.rb +8 -0
  183. data/test/thread_test.rb +122 -0
  184. data/test/tmate_test.rb +43 -0
  185. data/test/trace_test.rb +154 -0
  186. data/test/variables_test.rb +114 -0
  187. metadata +352 -0
@@ -0,0 +1,177 @@
1
+ require 'pp'
2
+ require 'stringio'
3
+ require 'socket'
4
+ require 'thread'
5
+ require 'ruby-debug-base'
6
+ require 'ruby-debug/processor'
7
+
8
+ module Debugger
9
+ self.handler = CommandProcessor.new
10
+
11
+ # the port number used for remote debugging
12
+ PORT = 8989 unless defined?(PORT)
13
+
14
+ # What file is used for debugger startup commands.
15
+ unless defined?(INITFILE)
16
+ if RUBY_PLATFORM =~ /mswin/
17
+ # Of course MS Windows has to be different
18
+ INITFILE = 'rdebug.ini'
19
+ HOME_DIR = (ENV['HOME'] ||
20
+ ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
21
+ else
22
+ INITFILE = '.rdebugrc'
23
+ HOME_DIR = ENV['HOME'].to_s
24
+ end
25
+ end
26
+
27
+ class << self
28
+ # gdb-style annotation mode. Used in GNU Emacs interface
29
+ attr_accessor :annotate
30
+
31
+ # in remote mode, wait for the remote connection
32
+ attr_accessor :wait_connection
33
+
34
+ # If set, a string to look for in caller() and is used to see
35
+ # if the call stack is truncated.
36
+ attr_accessor :start_sentinal
37
+
38
+ attr_reader :thread, :control_thread, :cmd_port, :ctrl_port
39
+
40
+ def interface=(value) # :nodoc:
41
+ handler.interface = value
42
+ end
43
+
44
+ #
45
+ # Starts a remote debugger.
46
+ #
47
+ def start_remote(host = nil, port = PORT)
48
+ return if @thread
49
+
50
+ self.interface = nil
51
+ start
52
+
53
+ if port.kind_of?(Array)
54
+ cmd_port, ctrl_port = port
55
+ else
56
+ cmd_port, ctrl_port = port, port + 1
57
+ end
58
+
59
+ ctrl_port = start_control(host, ctrl_port)
60
+
61
+ yield if block_given?
62
+
63
+ mutex = Mutex.new
64
+ proceed = ConditionVariable.new
65
+
66
+ server = TCPServer.new(host, cmd_port)
67
+ @cmd_port = cmd_port = server.addr[1]
68
+
69
+ @thread = DebugThread.new do
70
+ while (session = server.accept)
71
+ self.interface = RemoteInterface.new(session)
72
+ if wait_connection
73
+ mutex.synchronize do
74
+ proceed.signal
75
+ end
76
+ end
77
+ end
78
+ end
79
+ if wait_connection
80
+ mutex.synchronize do
81
+ proceed.wait(mutex)
82
+ end
83
+ end
84
+ end
85
+ alias start_server start_remote
86
+
87
+ def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc:
88
+ return @ctrl_port if defined?(@control_thread) && @control_thread
89
+ server = TCPServer.new(host, ctrl_port)
90
+ @ctrl_port = server.addr[1]
91
+ @control_thread = DebugThread.new do
92
+ while (session = server.accept)
93
+ interface = RemoteInterface.new(session)
94
+ processor = ControlCommandProcessor.new(interface)
95
+ processor.process_commands
96
+ end
97
+ end
98
+ @ctrl_port
99
+ end
100
+
101
+ #
102
+ # Connects to the remote debugger
103
+ #
104
+ def start_client(host = 'localhost', port = PORT)
105
+ require "socket"
106
+ interface = Debugger::LocalInterface.new
107
+ socket = TCPSocket.new(host, port)
108
+ puts "Connected."
109
+
110
+ catch(:exit) do
111
+ while (line = socket.gets)
112
+ case line
113
+ when /^PROMPT (.*)$/
114
+ input = interface.read_command($1)
115
+ throw :exit unless input
116
+ socket.puts input
117
+ when /^CONFIRM (.*)$/
118
+ input = interface.confirm($1)
119
+ throw :exit unless input
120
+ socket.puts input
121
+ else
122
+ print line
123
+ end
124
+ end
125
+ end
126
+ socket.close
127
+ end
128
+
129
+ # Runs normal debugger initialization scripts
130
+ # Reads and executes the commands from init file (if any) in the
131
+ # current working directory. This is only done if the current
132
+ # directory is different from your home directory. Thus, you can
133
+ # have more than one init file, one generic in your home directory,
134
+ # and another, specific to the program you are debugging, in the
135
+ # directory where you invoke ruby-debug.
136
+ def run_init_script(out = handler.interface)
137
+ cwd_script_file = File.expand_path(File.join(".", INITFILE))
138
+ run_script(cwd_script_file, out) if File.exists?(cwd_script_file)
139
+
140
+ home_script_file = File.expand_path(File.join(HOME_DIR, INITFILE))
141
+ run_script(home_script_file, out) if File.exists?(home_script_file) and
142
+ cwd_script_file != home_script_file
143
+ end
144
+
145
+ #
146
+ # Runs a script file
147
+ #
148
+ def run_script(file, out = handler.interface, verbose=false)
149
+ interface = ScriptInterface.new(File.expand_path(file), out)
150
+ processor = ControlCommandProcessor.new(interface)
151
+ processor.process_commands(verbose)
152
+ end
153
+ end
154
+ end
155
+
156
+ module Kernel
157
+
158
+ # Enters the debugger in the current thread after _steps_ line events occur.
159
+ # Before entering the debugger startup script is read.
160
+ #
161
+ # Setting _steps_ to 0 will cause a break in the debugger subroutine
162
+ # and not wait for a line event to occur. You will have to go "up 1"
163
+ # in order to be back in your debugged program rather than the
164
+ # debugger. Settings _steps_ to 0 could be useful you want to stop
165
+ # right after the last statement in some scope, because the next
166
+ # step will take you out of some scope.
167
+ def debugger(steps = 1)
168
+ Debugger.start
169
+ Debugger.run_init_script(StringIO.new)
170
+ if 0 == steps
171
+ Debugger.current_context.stop_frame = 0
172
+ else
173
+ Debugger.current_context.stop_next = steps
174
+ end
175
+ end
176
+ alias breakpoint debugger unless respond_to?(:breakpoint)
177
+ end
@@ -0,0 +1,227 @@
1
+ require 'columnize'
2
+ require 'ruby-debug/helper'
3
+
4
+ module Debugger
5
+ RUBY_DEBUG_DIR = File.expand_path(File.dirname(__FILE__)) unless
6
+ defined?(RUBY_DEBUG_DIR)
7
+
8
+ class Command # :nodoc:
9
+ SubcmdStruct=Struct.new(:name, :min, :short_help, :long_help) unless
10
+ defined?(SubcmdStruct)
11
+
12
+ include Columnize
13
+
14
+ # Find param in subcmds. param id downcased and can be abbreviated
15
+ # to the minimum length listed in the subcommands
16
+ def find(subcmds, param)
17
+ param.downcase!
18
+ for try_subcmd in subcmds do
19
+ if (param.size >= try_subcmd.min) and
20
+ (try_subcmd.name[0..param.size-1] == param)
21
+ return try_subcmd
22
+ end
23
+ end
24
+ return nil
25
+ end
26
+
27
+ class << self
28
+ def commands
29
+ @commands ||= []
30
+ end
31
+
32
+ DEF_OPTIONS = {
33
+ :allow_in_control => false,
34
+ :allow_in_post_mortem => true,
35
+ :event => true,
36
+ :always_run => 0,
37
+ :unknown => false,
38
+ :need_context => false,
39
+ } unless defined?(DEF_OPTIONS)
40
+
41
+ def inherited(klass)
42
+ DEF_OPTIONS.each do |o, v|
43
+ klass.options[o] = v if klass.options[o].nil?
44
+ end
45
+ commands << klass
46
+ end
47
+
48
+ def load_commands
49
+ Dir[File.join(Debugger.const_get(:RUBY_DEBUG_DIR), 'commands', '*')].each do |file|
50
+ require file if file =~ /\.rb$/
51
+ end
52
+ Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
53
+ include mod
54
+ end
55
+ end
56
+
57
+ def method_missing(meth, *args, &block)
58
+ if meth.to_s =~ /^(.+?)=$/
59
+ @options[$1.intern] = args.first
60
+ else
61
+ if @options.has_key?(meth)
62
+ @options[meth]
63
+ else
64
+ super
65
+ end
66
+ end
67
+ end
68
+
69
+ def options
70
+ @options ||= {}
71
+ end
72
+
73
+ def settings_map
74
+ @@settings_map ||= {}
75
+ end
76
+ private :settings_map
77
+
78
+ def settings
79
+ unless true and defined? @settings and @settings
80
+ @settings = Object.new
81
+ map = settings_map
82
+ c = class << @settings; self end
83
+ if c.respond_to?(:funcall)
84
+ c.funcall(:define_method, :[]) do |name|
85
+ raise "No such setting #{name}" unless map.has_key?(name)
86
+ map[name][:getter].call
87
+ end
88
+ else
89
+ c.send(:define_method, :[]) do |name|
90
+ raise "No such setting #{name}" unless map.has_key?(name)
91
+ map[name][:getter].call
92
+ end
93
+ end
94
+ c = class << @settings; self end
95
+ if c.respond_to?(:funcall)
96
+ c.funcall(:define_method, :[]=) do |name, value|
97
+ raise "No such setting #{name}" unless map.has_key?(name)
98
+ map[name][:setter].call(value)
99
+ end
100
+ else
101
+ c.send(:define_method, :[]=) do |name, value|
102
+ raise "No such setting #{name}" unless map.has_key?(name)
103
+ map[name][:setter].call(value)
104
+ end
105
+ end
106
+ end
107
+ @settings
108
+ end
109
+
110
+ def register_setting_var(name, default)
111
+ var_name = "@@#{name}"
112
+ class_variable_set(var_name, default)
113
+ register_setting_get(name) { class_variable_get(var_name) }
114
+ register_setting_set(name) { |value| class_variable_set(var_name, value) }
115
+ end
116
+
117
+ def register_setting_get(name, &block)
118
+ settings_map[name] ||= {}
119
+ settings_map[name][:getter] = block
120
+ end
121
+
122
+ def register_setting_set(name, &block)
123
+ settings_map[name] ||= {}
124
+ settings_map[name][:setter] = block
125
+ end
126
+ end
127
+
128
+ register_setting_var(:basename, false) # use basename in showing files?
129
+ register_setting_var(:callstyle, :last)
130
+ register_setting_var(:debuggertesting, false)
131
+ register_setting_var(:force_stepping, false)
132
+ register_setting_var(:full_path, true)
133
+ register_setting_var(:listsize, 10) # number of lines in list command
134
+ register_setting_var(:stack_trace_on_error, false)
135
+ register_setting_var(:tracing_plus, false) # different linetrace lines?
136
+
137
+ # width of line output. Use COLUMNS value if it exists and is
138
+ # not too rediculously large.
139
+ width = ENV['COLUMNS'].to_i
140
+ width = 80 unless width > 10
141
+ register_setting_var(:width, width)
142
+
143
+ if not defined? Debugger::ARGV
144
+ Debugger::ARGV = ARGV.clone
145
+ end
146
+ register_setting_var(:argv, Debugger::ARGV)
147
+
148
+ def initialize(state)
149
+ @state = state
150
+ end
151
+
152
+ def match(input)
153
+ @match = regexp.match(input)
154
+ end
155
+
156
+ protected
157
+
158
+ # FIXME: use delegate?
159
+ def errmsg(*args)
160
+ @state.errmsg(*args)
161
+ end
162
+
163
+ def print(*args)
164
+ @state.print(*args)
165
+ end
166
+
167
+ def confirm(msg)
168
+ @state.confirm(msg) == 'y'
169
+ end
170
+
171
+ def debug_eval(str, b = get_binding)
172
+ begin
173
+ val = eval(str, b)
174
+ rescue StandardError, ScriptError => e
175
+ if Command.settings[:stack_trace_on_error]
176
+ at = eval("caller(1)", b)
177
+ print "%s:%s\n", at.shift, e.to_s.sub(/\(eval\):1:(in `.*?':)?/, '')
178
+ for i in at
179
+ print "\tfrom %s\n", i
180
+ end
181
+ else
182
+ print "#{e.class} Exception: #{e.message}\n"
183
+ end
184
+ throw :debug_error
185
+ end
186
+ end
187
+
188
+ def debug_silent_eval(str)
189
+ begin
190
+ eval(str, get_binding)
191
+ rescue StandardError, ScriptError
192
+ nil
193
+ end
194
+ end
195
+
196
+ def get_binding
197
+ @state.context.frame_binding(@state.frame_pos)
198
+ end
199
+
200
+ def line_at(file, line)
201
+ Debugger.line_at(file, line)
202
+ end
203
+
204
+ def get_context(thnum)
205
+ Debugger.contexts.find{|c| c.thnum == thnum}
206
+ end
207
+ end
208
+
209
+ Command.load_commands
210
+
211
+ # Returns setting object.
212
+ # Use Debugger.settings[] and Debugger.settings[]= methods to query and set
213
+ # debugger settings. These settings are available:
214
+ #
215
+ # - :autolist - automatically calls 'list' command on breakpoint
216
+ # - :autoeval - evaluates input in the current binding if it's not recognized as a debugger command
217
+ # - :autoirb - automatically calls 'irb' command on breakpoint
218
+ # - :stack_trace_on_error - shows full stack trace if eval command results with an exception
219
+ # - :frame_full_path - displays full paths when showing frame stack
220
+ # - :frame_class_names - displays method's class name when showing frame stack
221
+ # - :reload_source_on_change - makes 'list' command to always display up-to-date source code
222
+ # - :force_stepping - stepping command asways move to the new line
223
+ #
224
+ def self.settings
225
+ Command.settings
226
+ end
227
+ end
@@ -0,0 +1,153 @@
1
+ module Debugger
2
+
3
+ # Implements debugger "break" command.
4
+ class AddBreakpoint < Command
5
+ self.allow_in_control = true
6
+
7
+ def regexp
8
+ / ^\s*
9
+ b(?:reak)?
10
+ (?: \s+ #{Position_regexp})? \s*
11
+ (?: \s+ (.*))? \s*
12
+ $
13
+ /x
14
+ end
15
+
16
+ def execute
17
+ if @match[1]
18
+ line, _, _, expr = @match.captures
19
+ else
20
+ _, file, line, expr = @match.captures
21
+ end
22
+ if expr
23
+ if expr !~ /^\s*if\s+(.+)/
24
+ if file or line
25
+ errmsg "Expecting 'if' in breakpoint condition; got: #{expr}.\n"
26
+ else
27
+ errmsg "Invalid breakpoint location: #{expr}.\n"
28
+ end
29
+ return
30
+ else
31
+ expr = $1
32
+ end
33
+ end
34
+
35
+ brkpt_filename = nil
36
+ if file.nil?
37
+ unless @state.context
38
+ errmsg "We are not in a state that has an associated file.\n"
39
+ return
40
+ end
41
+ brkpt_filename = @state.file
42
+ file = File.basename(@state.file)
43
+ if line.nil?
44
+ # Set breakpoint at current line
45
+ line = @state.line.to_s
46
+ end
47
+ elsif line !~ /^\d+$/
48
+ # See if "line" is a method/function name
49
+ klass = debug_silent_eval(file)
50
+ if klass && klass.kind_of?(Module)
51
+ class_name = klass.name if klass
52
+ else
53
+ errmsg "Unknown class #{file}.\n"
54
+ throw :debug_error
55
+ end
56
+ else
57
+ # FIXME: This should be done in LineCache.
58
+ file = File.expand_path(file) if file.index(File::SEPARATOR) || \
59
+ File::ALT_SEPARATOR && file.index(File::ALT_SEPARATOR)
60
+ brkpt_filename = file
61
+ end
62
+
63
+ if line =~ /^\d+$/
64
+ line = line.to_i
65
+ if LineCache.cache(brkpt_filename, Command.settings[:reload_source_on_change])
66
+ last_line = LineCache.size(brkpt_filename)
67
+ if line > last_line
68
+ errmsg("There are only %d lines in file \"%s\".\n", last_line, file)
69
+ return
70
+ end
71
+ unless LineCache.trace_line_numbers(brkpt_filename).member?(line)
72
+ errmsg("Line %d is not a stopping point in file \"%s\".\n", line, file)
73
+ return
74
+ end
75
+ else
76
+ errmsg("No source file named %s\n" % file)
77
+ return unless confirm("Set breakpoint anyway? (y/n) ")
78
+ end
79
+
80
+ unless @state.context
81
+ errmsg "We are not in a state we can add breakpoints.\n"
82
+ return
83
+ end
84
+ b = Debugger.add_breakpoint brkpt_filename, line, expr
85
+ print "Breakpoint %d file %s, line %s\n", b.id, brkpt_filename, line.to_s
86
+ unless syntax_valid?(expr)
87
+ errmsg("Expression \"#{expr}\" syntactically incorrect; breakpoint disabled.\n")
88
+ b.enabled = false
89
+ end
90
+ else
91
+ method = line.intern.id2name
92
+ b = Debugger.add_breakpoint class_name, method, expr
93
+ print "Breakpoint %d at %s::%s\n", b.id, class_name, method.to_s
94
+ end
95
+ end
96
+
97
+ class << self
98
+ def help_command
99
+ 'break'
100
+ end
101
+
102
+ def help(cmd)
103
+ %{
104
+ b[reak] file:line [if expr]
105
+ b[reak] class(.|#)method [if expr]
106
+ \tset breakpoint to some position, (optionally) if expr == true
107
+ }
108
+ end
109
+ end
110
+ end
111
+
112
+ # Implements debugger "delete" command.
113
+ class DeleteBreakpointCommand < Command
114
+ self.allow_in_control = true
115
+
116
+ def regexp
117
+ /^\s *del(?:ete)? (?:\s+(.*))?$/ix
118
+ end
119
+
120
+ def execute
121
+ unless @state.context
122
+ errmsg "We are not in a state we can delete breakpoints.\n"
123
+ return
124
+ end
125
+ brkpts = @match[1]
126
+ unless brkpts
127
+ if confirm("Delete all breakpoints? (y or n) ")
128
+ Debugger.breakpoints.clear
129
+ end
130
+ else
131
+ brkpts.split(/[ \t]+/).each do |pos|
132
+ pos = get_int(pos, "Delete", 1)
133
+ return unless pos
134
+ unless Debugger.remove_breakpoint(pos)
135
+ errmsg "No breakpoint number %d\n", pos
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ class << self
142
+ def help_command
143
+ 'delete'
144
+ end
145
+
146
+ def help(cmd)
147
+ %{
148
+ del[ete][ nnn...]\tdelete some or all breakpoints
149
+ }
150
+ end
151
+ end
152
+ end
153
+ end