ruby-debug-base193 0.0.1

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.
@@ -0,0 +1,266 @@
1
+ #!/usr/bin/env rake
2
+ # -*- Ruby -*-
3
+ require 'rubygems'
4
+ require 'rake/gempackagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+ require 'rake/extensiontask'
8
+
9
+ Rake::ExtensionTask.new('ruby_debug')
10
+
11
+ SO_NAME = "ruby_debug.so"
12
+
13
+ # ------- Default Package ----------
14
+ RUBY_DEBUG_VERSION = open("ext/ruby_debug/ruby_debug.c") do |f|
15
+ f.grep(/^#define DEBUG_VERSION/).first[/"(.+)"/,1]
16
+ end
17
+
18
+ RUBY_DEBUG_TEENY = ".0"
19
+ RUBY_DEBUG_BASE_TEENY = ".0"
20
+
21
+ COMMON_FILES = FileList[
22
+ 'AUTHORS',
23
+ 'CHANGES',
24
+ 'LICENSE',
25
+ 'README',
26
+ 'Rakefile',
27
+ ]
28
+
29
+ CLI_TEST_FILE_LIST = FileList['test/cli/commands/unit/*.rb',
30
+ 'test/cli/commands/*_test.rb',
31
+ 'test/cli/**/*_test.rb',
32
+ 'test/test-*.rb']
33
+ CLI_FILES = COMMON_FILES + FileList[
34
+ "cli/**/*",
35
+ 'ChangeLog',
36
+ 'bin/*',
37
+ 'doc/rdebug.1',
38
+ 'test/**/data/*.cmd',
39
+ 'test/**/data/*.right',
40
+ 'test/**/*.rb',
41
+ 'rdbg.rb',
42
+ CLI_TEST_FILE_LIST
43
+ ]
44
+
45
+ BASE_TEST_FILE_LIST = %w(
46
+ test/base/base.rb
47
+ test/base/binding.rb
48
+ test/base/catchpoint.rb)
49
+ BASE_FILES = COMMON_FILES + FileList[
50
+ 'ext/ruby_debug/breakpoint.c',
51
+ 'ext/ruby_debug/extconf.rb',
52
+ 'ext/ruby_debug/ruby_debug.c',
53
+ 'ext/ruby_debug/ruby_debug.h',
54
+ 'ext/win32/*',
55
+ 'lib/**/*',
56
+ BASE_TEST_FILE_LIST,
57
+ ]
58
+
59
+ desc "Test everything."
60
+ task :test => :test_base do
61
+ Rake::TestTask.new(:test) do |t|
62
+ t.libs << './ext'
63
+ t.libs << './lib'
64
+ t.libs << './cli'
65
+ t.test_files = CLI_TEST_FILE_LIST
66
+ t.verbose = true
67
+ end
68
+ end
69
+
70
+ desc "Test ruby-debug-base."
71
+ task :test_base => :lib do
72
+ Rake::TestTask.new(:test_base) do |t|
73
+ t.libs << './ext'
74
+ t.libs << './lib'
75
+ t.test_files = FileList[BASE_TEST_FILE_LIST]
76
+ t.verbose = true
77
+ end
78
+ end
79
+
80
+ desc "Test everything - same as test."
81
+ task :check => :test
82
+
83
+ desc "Create the core ruby-debug shared library extension"
84
+ task :lib do
85
+ Dir.chdir("ext") do
86
+ system("#{Gem.ruby} extconf.rb && make")
87
+ end
88
+ end
89
+
90
+ desc "Compile Emacs code"
91
+ task :emacs => "emacs/rdebug.elc"
92
+ file "emacs/rdebug.elc" => ["emacs/elisp-comp", "emacs/rdebug.el"] do
93
+ Dir.chdir("emacs") do
94
+ system("./elisp-comp ./rdebug.el")
95
+ end
96
+ end
97
+
98
+ desc "Create a GNU-style ChangeLog via svn2cl"
99
+ task :ChangeLog do
100
+ system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk")
101
+ system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/ext -o ext/ChangeLog")
102
+ system("svn2cl --authors=svn2cl_usermap svn://rubyforge.org/var/svn/ruby-debug/trunk/lib -o lib/ChangeLog")
103
+ end
104
+
105
+ # Base GEM Specification
106
+ base_spec = Gem::Specification.new do |spec|
107
+ spec.name = "ruby-debug-base19"
108
+
109
+ spec.homepage = "http://rubyforge.org/projects/ruby-debug19/"
110
+ spec.summary = "Fast Ruby debugger - core component"
111
+ spec.description = <<-EOF
112
+ ruby-debug-base19 is a fast implementation of the standard Ruby debugger debug.rb.
113
+ It is implemented by utilizing a new Ruby C API hook. The core component
114
+ provides support that front-ends can build on. It provides breakpoint
115
+ handling, bindings for stack frames among other things.
116
+ EOF
117
+
118
+ spec.version = RUBY_DEBUG_VERSION + RUBY_DEBUG_BASE_TEENY
119
+
120
+ spec.authors = ["Kent Sibilev", "Mark Moseley"]
121
+ spec.email = "mark@fast-software.com"
122
+ spec.platform = Gem::Platform::RUBY
123
+ spec.require_path = "lib"
124
+ spec.extensions = ["ext/ruby_debug/extconf.rb"]
125
+ spec.files = BASE_FILES.to_a
126
+
127
+ spec.required_ruby_version = '>= 1.8.2'
128
+ spec.date = Time.now
129
+ spec.rubyforge_project = 'ruby-debug19'
130
+ spec.add_dependency('ruby_core_source', '>= 0.1.4')
131
+ spec.add_dependency('linecache19', '>= 0.5.11')
132
+
133
+ spec.test_files = FileList[BASE_TEST_FILE_LIST]
134
+
135
+ # rdoc
136
+ spec.has_rdoc = true
137
+ spec.extra_rdoc_files = ['README', 'ext/ruby_debug/ruby_debug.c']
138
+ end
139
+
140
+ cli_spec = Gem::Specification.new do |spec|
141
+ spec.name = "ruby-debug19"
142
+
143
+ spec.homepage = "http://rubyforge.org/projects/ruby-debug19/"
144
+ spec.summary = "Command line interface (CLI) for ruby-debug-base19"
145
+ spec.description = <<-EOF
146
+ A generic command line interface for ruby-debug.
147
+ EOF
148
+
149
+ spec.version = RUBY_DEBUG_VERSION + RUBY_DEBUG_TEENY
150
+
151
+ spec.authors = ["Kent Sibilev", "Mark Moseley"]
152
+ spec.email = "mark@fast-software.com"
153
+ spec.platform = Gem::Platform::RUBY
154
+ spec.require_path = "cli"
155
+ spec.bindir = "bin"
156
+ spec.executables = ["rdebug"]
157
+ spec.files = CLI_FILES.to_a
158
+
159
+ spec.required_ruby_version = '>= 1.8.2'
160
+ spec.date = Time.now
161
+ spec.rubyforge_project = 'ruby-debug'
162
+ spec.add_dependency('columnize', '>= 0.3.1')
163
+ spec.add_dependency('linecache19', '>= 0.5.11')
164
+ spec.add_dependency('ruby-debug-base19', '>= 0.12.0')
165
+
166
+ # FIXME: work out operational logistics for this
167
+ # spec.test_files = FileList[CLI_TEST_FILE_LIST]
168
+
169
+ # rdoc
170
+ spec.has_rdoc = true
171
+ spec.extra_rdoc_files = ['README']
172
+ end
173
+
174
+ # Rake task to build the default package
175
+ Rake::GemPackageTask.new(base_spec) do |pkg|
176
+ pkg.need_tar = true
177
+ end
178
+ Rake::GemPackageTask.new(cli_spec) do |pkg|
179
+ pkg.need_tar = true
180
+ end
181
+
182
+ task :default => [:package]
183
+
184
+ # Windows specification
185
+ win_spec = base_spec.clone
186
+ win_spec.extensions = []
187
+ ## win_spec.platform = Gem::Platform::WIN32 # deprecated
188
+ win_spec.platform = 'mswin32'
189
+ win_spec.files += ["lib/#{SO_NAME}"]
190
+
191
+ desc "Create Windows Gem"
192
+ task :win32_gem do
193
+ # Copy the win32 extension the top level directory
194
+ current_dir = File.expand_path(File.dirname(__FILE__))
195
+ source = File.join(current_dir, "ext", "win32", SO_NAME)
196
+ target = File.join(current_dir, "lib", SO_NAME)
197
+ cp(source, target)
198
+
199
+ # Create the gem, then move it to pkg.
200
+ Gem::Builder.new(win_spec).build
201
+ gem_file = "#{win_spec.name}-#{win_spec.version}-#{win_spec.platform}.gem"
202
+ mv(gem_file, "pkg/#{gem_file}")
203
+
204
+ # Remove win extension from top level directory.
205
+ rm(target)
206
+ end
207
+
208
+ desc "Publish ruby-debug to RubyForge."
209
+ task :publish do
210
+ require 'rake/contrib/sshpublisher'
211
+
212
+ # Get ruby-debug path.
213
+ ruby_debug_path = File.expand_path(File.dirname(__FILE__))
214
+
215
+ Rake::SshDirPublisher.new("kent@rubyforge.org",
216
+ "/var/www/gforge-projects/ruby-debug", ruby_debug_path)
217
+ end
218
+
219
+ desc "Remove built files"
220
+ task :clean do
221
+ cd "ext" do
222
+ if File.exists?("Makefile")
223
+ sh "make clean"
224
+ rm "Makefile"
225
+ end
226
+ derived_files = Dir.glob(".o") + Dir.glob("*.so")
227
+ rm derived_files unless derived_files.empty?
228
+ end
229
+ end
230
+
231
+ # --------- RDoc Documentation ------
232
+ desc "Generate rdoc documentation"
233
+ Rake::RDocTask.new("rdoc") do |rdoc|
234
+ rdoc.rdoc_dir = 'doc/rdoc'
235
+ rdoc.title = "ruby-debug"
236
+ # Show source inline with line numbers
237
+ rdoc.options << "--inline-source" << "--line-numbers"
238
+ # Make the readme file the start page for the generated html
239
+ rdoc.options << '--main' << 'README'
240
+ rdoc.rdoc_files.include('bin/**/*',
241
+ 'cli/ruby-debug/commands/*.rb',
242
+ 'lib/**/*.rb',
243
+ 'ext/**/ruby_debug.c',
244
+ 'README',
245
+ 'LICENSE')
246
+ end
247
+
248
+ desc "Publish the release files to RubyForge."
249
+ task :rubyforge_upload do
250
+ `rubyforge login`
251
+ release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} '#{PKG_NAME}-#{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.gem"
252
+ puts release_command
253
+ system(release_command)
254
+ end
255
+
256
+ PKG_NAME = 'ruby-debug'
257
+ desc "Publish the release files to RubyForge."
258
+ task :rubyforge_upload do
259
+ `rubyforge login`
260
+ for pkg_name in ['ruby-debug', 'ruby-debug-base'] do
261
+ pkg_file_name = "#{pkg_name}-#{pkg_version}"
262
+ release_command = "rubyforge add_release ruby-debug #{pkg_name} '#{pkg_file_name}' pkg/#{pkg_file_name}.gem"
263
+ puts release_command
264
+ system(release_command)
265
+ end
266
+ end
@@ -0,0 +1,578 @@
1
+ #include <ruby.h>
2
+ #include <stdio.h>
3
+ #include <vm_core.h>
4
+ #include <iseq.h>
5
+ #include "ruby_debug.h"
6
+
7
+ VALUE rdebug_breakpoints = Qnil;
8
+ VALUE rdebug_catchpoints;
9
+
10
+ static VALUE cBreakpoint;
11
+ static ID idEval;
12
+
13
+ static VALUE
14
+ eval_expression(VALUE args)
15
+ {
16
+ return rb_funcall2(rb_mKernel, idEval, 2, RARRAY_PTR(args));
17
+ }
18
+
19
+ int
20
+ check_breakpoint_hit_condition(VALUE breakpoint)
21
+ {
22
+ debug_breakpoint_t *debug_breakpoint;
23
+
24
+ if(breakpoint == Qnil)
25
+ return 0;
26
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
27
+
28
+ debug_breakpoint->hit_count++;
29
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
30
+ switch(debug_breakpoint->hit_condition)
31
+ {
32
+ case HIT_COND_NONE:
33
+ return 1;
34
+ case HIT_COND_GE:
35
+ {
36
+ if(debug_breakpoint->hit_count >= debug_breakpoint->hit_value)
37
+ return 1;
38
+ break;
39
+ }
40
+ case HIT_COND_EQ:
41
+ {
42
+ if(debug_breakpoint->hit_count == debug_breakpoint->hit_value)
43
+ return 1;
44
+ break;
45
+ }
46
+ case HIT_COND_MOD:
47
+ {
48
+ if(debug_breakpoint->hit_count % debug_breakpoint->hit_value == 0)
49
+ return 1;
50
+ break;
51
+ }
52
+ }
53
+ return 0;
54
+ }
55
+
56
+ static int
57
+ check_breakpoint_by_pos(VALUE breakpoint, const char *file, int line)
58
+ {
59
+ debug_breakpoint_t *debug_breakpoint;
60
+
61
+ if(breakpoint == Qnil)
62
+ return 0;
63
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
64
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
65
+ if(debug_breakpoint->type != BP_POS_TYPE)
66
+ return 0;
67
+ if(debug_breakpoint->pos.line != line)
68
+ return 0;
69
+ if(filename_cmp(debug_breakpoint->source, file))
70
+ return 1;
71
+ return 0;
72
+ }
73
+
74
+ int
75
+ check_breakpoint_by_method(VALUE breakpoint, VALUE klass, ID mid, VALUE self)
76
+ {
77
+ debug_breakpoint_t *debug_breakpoint;
78
+
79
+ if(breakpoint == Qnil)
80
+ return 0;
81
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
82
+ if (!Qtrue == debug_breakpoint->enabled) return 0;
83
+ if(debug_breakpoint->type != BP_METHOD_TYPE)
84
+ return 0;
85
+ if(debug_breakpoint->pos.mid != mid)
86
+ return 0;
87
+ if(classname_cmp(debug_breakpoint->source, klass))
88
+ return 1;
89
+ if ((rb_type(self) == T_CLASS) &&
90
+ classname_cmp(debug_breakpoint->source, self))
91
+ return 1;
92
+ return 0;
93
+ }
94
+
95
+ VALUE
96
+ check_breakpoints_by_pos(debug_context_t *debug_context, const char *file, int line)
97
+ {
98
+ VALUE breakpoint;
99
+ int i;
100
+
101
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
102
+ return Qnil;
103
+
104
+ if(check_breakpoint_by_pos(debug_context->breakpoint, file, line))
105
+ return debug_context->breakpoint;
106
+
107
+ if(RARRAY_LEN(rdebug_breakpoints) == 0)
108
+ return Qnil;
109
+ for(i = 0; i < RARRAY_LEN(rdebug_breakpoints); i++)
110
+ {
111
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
112
+ if(check_breakpoint_by_pos(breakpoint, file, line))
113
+ return breakpoint;
114
+ }
115
+ return Qnil;
116
+ }
117
+
118
+ VALUE
119
+ check_breakpoints_by_method(debug_context_t *debug_context, VALUE klass, ID mid, VALUE self)
120
+ {
121
+ VALUE breakpoint;
122
+ int i;
123
+
124
+ if(!CTX_FL_TEST(debug_context, CTX_FL_ENABLE_BKPT))
125
+ return Qnil;
126
+
127
+ if(check_breakpoint_by_method(debug_context->breakpoint, klass, mid, self))
128
+ return debug_context->breakpoint;
129
+
130
+ if(RARRAY_LEN(rdebug_breakpoints) == 0)
131
+ return Qnil;
132
+ for(i = 0; i < RARRAY_LEN(rdebug_breakpoints); i++)
133
+ {
134
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
135
+ if(check_breakpoint_by_method(breakpoint, klass, mid, self))
136
+ return breakpoint;
137
+ }
138
+ return Qnil;
139
+ }
140
+
141
+ int
142
+ check_breakpoint_expression(VALUE breakpoint, VALUE binding)
143
+ {
144
+ debug_breakpoint_t *debug_breakpoint;
145
+ VALUE args, expr_result;
146
+
147
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
148
+ if(NIL_P(debug_breakpoint->expr))
149
+ return 1;
150
+
151
+ args = rb_ary_new3(2, debug_breakpoint->expr, binding);
152
+ expr_result = rb_protect(eval_expression, args, 0);
153
+ return RTEST(expr_result);
154
+ }
155
+
156
+ static void
157
+ breakpoint_mark(void *data)
158
+ {
159
+ debug_breakpoint_t *breakpoint;
160
+ breakpoint = (debug_breakpoint_t *)data;
161
+ rb_gc_mark(breakpoint->source);
162
+ rb_gc_mark(breakpoint->expr);
163
+ }
164
+
165
+ VALUE
166
+ create_breakpoint_from_args(int argc, VALUE *argv, int id)
167
+ {
168
+ VALUE source, pos, expr;
169
+ debug_breakpoint_t *breakpoint;
170
+ int type;
171
+
172
+ if(rb_scan_args(argc, argv, "21", &source, &pos, &expr) == 2)
173
+ {
174
+ expr = Qnil;
175
+ }
176
+ type = FIXNUM_P(pos) ? BP_POS_TYPE : BP_METHOD_TYPE;
177
+ if(type == BP_POS_TYPE)
178
+ source = StringValue(source);
179
+ else
180
+ pos = StringValue(pos);
181
+ breakpoint = ALLOC(debug_breakpoint_t);
182
+ breakpoint->id = id;
183
+ breakpoint->source = source;
184
+ breakpoint->type = type;
185
+ if(type == BP_POS_TYPE)
186
+ breakpoint->pos.line = FIX2INT(pos);
187
+ else
188
+ breakpoint->pos.mid = rb_intern(RSTRING_PTR(pos));
189
+ breakpoint->enabled = Qtrue;
190
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
191
+ breakpoint->hit_count = 0;
192
+ breakpoint->hit_value = 0;
193
+ breakpoint->hit_condition = HIT_COND_NONE;
194
+ return Data_Wrap_Struct(cBreakpoint, breakpoint_mark, xfree, breakpoint);
195
+ }
196
+
197
+ /*
198
+ * call-seq:
199
+ * Debugger.remove_breakpoint(id) -> breakpoint
200
+ *
201
+ * Removes breakpoint by its id.
202
+ * <i>id</i> is an identificator of a breakpoint.
203
+ */
204
+ VALUE
205
+ rdebug_remove_breakpoint(VALUE self, VALUE id_value)
206
+ {
207
+ int i;
208
+ int id;
209
+ VALUE breakpoint;
210
+ debug_breakpoint_t *debug_breakpoint;
211
+
212
+ id = FIX2INT(id_value);
213
+
214
+ for( i = 0; i < RARRAY_LEN(rdebug_breakpoints); i += 1 )
215
+ {
216
+ breakpoint = rb_ary_entry(rdebug_breakpoints, i);
217
+ Data_Get_Struct(breakpoint, debug_breakpoint_t, debug_breakpoint);
218
+ if(debug_breakpoint->id == id)
219
+ {
220
+ rb_ary_delete_at(rdebug_breakpoints, i);
221
+ return breakpoint;
222
+ }
223
+ }
224
+ return Qnil;
225
+ }
226
+
227
+ /*
228
+ * call-seq:
229
+ * Debugger.catchpoints -> hash
230
+ *
231
+ * Returns a current catchpoints, which is a hash exception names that will
232
+ * trigger a debugger when raised. The values are the number of times taht
233
+ * catchpoint was hit, initially 0.
234
+ */
235
+ VALUE
236
+ debug_catchpoints(VALUE self)
237
+ {
238
+ return rdebug_catchpoints;
239
+ }
240
+
241
+ /*
242
+ * call-seq:
243
+ * Debugger.catchpoint(string) -> string
244
+ *
245
+ * Sets catchpoint. Returns the string passed.
246
+ */
247
+ VALUE
248
+ rdebug_add_catchpoint(VALUE self, VALUE value)
249
+ {
250
+ if (TYPE(value) != T_STRING) {
251
+ rb_raise(rb_eTypeError, "value of a catchpoint must be String");
252
+ }
253
+ rb_hash_aset(rdebug_catchpoints, rb_str_dup(value), INT2FIX(0));
254
+ return value;
255
+ }
256
+
257
+ /*
258
+ * call-seq:
259
+ * context.breakpoint -> breakpoint
260
+ *
261
+ * Returns a context-specific temporary Breakpoint object.
262
+ */
263
+ VALUE
264
+ context_breakpoint(VALUE self)
265
+ {
266
+ debug_context_t *debug_context;
267
+
268
+ Data_Get_Struct(self, debug_context_t, debug_context);
269
+ return debug_context->breakpoint;
270
+ }
271
+
272
+ /*
273
+ * call-seq:
274
+ * context.set_breakpoint(source, pos, condition = nil) -> breakpoint
275
+ *
276
+ * Sets a context-specific temporary breakpoint, which can be used to implement
277
+ * 'Run to Cursor' debugger function. When this breakpoint is reached, it will be
278
+ * cleared out.
279
+ *
280
+ * <i>source</i> is a name of a file or a class.
281
+ * <i>pos</i> is a line number or a method name if <i>source</i> is a class name.
282
+ * <i>condition</i> is a string which is evaluated to +true+ when this breakpoint
283
+ * is activated.
284
+ */
285
+ VALUE
286
+ context_set_breakpoint(int argc, VALUE *argv, VALUE self)
287
+ {
288
+ VALUE result;
289
+ debug_context_t *debug_context;
290
+
291
+ Data_Get_Struct(self, debug_context_t, debug_context);
292
+ result = create_breakpoint_from_args(argc, argv, 0);
293
+ debug_context->breakpoint = result;
294
+ return result;
295
+ }
296
+
297
+ /*
298
+ * call-seq:
299
+ * breakpoint.enabled?
300
+ *
301
+ * Returns whether breakpoint is enabled or not.
302
+ */
303
+ static VALUE
304
+ breakpoint_enabled(VALUE self)
305
+ {
306
+ debug_breakpoint_t *breakpoint;
307
+
308
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
309
+ return breakpoint->enabled;
310
+ }
311
+
312
+ /*
313
+ * call-seq:
314
+ * breakpoint.enabled = bool
315
+ *
316
+ * Enables or disables breakpoint.
317
+ */
318
+ static VALUE
319
+ breakpoint_set_enabled(VALUE self, VALUE bool)
320
+ {
321
+ debug_breakpoint_t *breakpoint;
322
+
323
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
324
+ return breakpoint->enabled = bool;
325
+ }
326
+
327
+ /*
328
+ * call-seq:
329
+ * breakpoint.source -> string
330
+ *
331
+ * Returns a source of the breakpoint.
332
+ */
333
+ static VALUE
334
+ breakpoint_source(VALUE self)
335
+ {
336
+ debug_breakpoint_t *breakpoint;
337
+
338
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
339
+ return breakpoint->source;
340
+ }
341
+
342
+ /*
343
+ * call-seq:
344
+ * breakpoint.source = string
345
+ *
346
+ * Sets the source of the breakpoint.
347
+ */
348
+ static VALUE
349
+ breakpoint_set_source(VALUE self, VALUE value)
350
+ {
351
+ debug_breakpoint_t *breakpoint;
352
+
353
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
354
+ breakpoint->source = StringValue(value);
355
+ return value;
356
+ }
357
+
358
+ /*
359
+ * call-seq:
360
+ * breakpoint.pos -> string or int
361
+ *
362
+ * Returns the position of this breakpoint.
363
+ */
364
+ static VALUE
365
+ breakpoint_pos(VALUE self)
366
+ {
367
+ debug_breakpoint_t *breakpoint;
368
+
369
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
370
+ if(breakpoint->type == BP_METHOD_TYPE)
371
+ return rb_str_new2(rb_id2name(breakpoint->pos.mid));
372
+ else
373
+ return INT2FIX(breakpoint->pos.line);
374
+ }
375
+
376
+ /*
377
+ * call-seq:
378
+ * breakpoint.pos = string or int
379
+ *
380
+ * Sets the position of this breakpoint.
381
+ */
382
+ static VALUE
383
+ breakpoint_set_pos(VALUE self, VALUE value)
384
+ {
385
+ debug_breakpoint_t *breakpoint;
386
+
387
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
388
+ if(breakpoint->type == BP_METHOD_TYPE)
389
+ {
390
+ breakpoint->pos.mid = rb_to_id(StringValue(value));
391
+ }
392
+ else
393
+ breakpoint->pos.line = FIX2INT(value);
394
+ return value;
395
+ }
396
+
397
+ /*
398
+ * call-seq:
399
+ * breakpoint.expr -> string
400
+ *
401
+ * Returns a codition expression when this breakpoint should be activated.
402
+ */
403
+ static VALUE
404
+ breakpoint_expr(VALUE self)
405
+ {
406
+ debug_breakpoint_t *breakpoint;
407
+
408
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
409
+ return breakpoint->expr;
410
+ }
411
+
412
+ /*
413
+ * call-seq:
414
+ * breakpoint.expr = string | nil
415
+ *
416
+ * Sets the codition expression when this breakpoint should be activated.
417
+ */
418
+ static VALUE
419
+ breakpoint_set_expr(VALUE self, VALUE expr)
420
+ {
421
+ debug_breakpoint_t *breakpoint;
422
+
423
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
424
+ breakpoint->expr = NIL_P(expr) ? expr: StringValue(expr);
425
+ return expr;
426
+ }
427
+
428
+ /*
429
+ * call-seq:
430
+ * breakpoint.id -> int
431
+ *
432
+ * Returns id of the breakpoint.
433
+ */
434
+ static VALUE
435
+ breakpoint_id(VALUE self)
436
+ {
437
+ debug_breakpoint_t *breakpoint;
438
+
439
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
440
+ return INT2FIX(breakpoint->id);
441
+ }
442
+
443
+ /*
444
+ * call-seq:
445
+ * breakpoint.hit_count -> int
446
+ *
447
+ * Returns the hit count of the breakpoint.
448
+ */
449
+ static VALUE
450
+ breakpoint_hit_count(VALUE self)
451
+ {
452
+ debug_breakpoint_t *breakpoint;
453
+
454
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
455
+ return INT2FIX(breakpoint->hit_count);
456
+ }
457
+
458
+ /*
459
+ * call-seq:
460
+ * breakpoint.hit_value -> int
461
+ *
462
+ * Returns the hit value of the breakpoint.
463
+ */
464
+ static VALUE
465
+ breakpoint_hit_value(VALUE self)
466
+ {
467
+ debug_breakpoint_t *breakpoint;
468
+
469
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
470
+ return INT2FIX(breakpoint->hit_value);
471
+ }
472
+
473
+ /*
474
+ * call-seq:
475
+ * breakpoint.hit_value = int
476
+ *
477
+ * Sets the hit value of the breakpoint.
478
+ */
479
+ static VALUE
480
+ breakpoint_set_hit_value(VALUE self, VALUE value)
481
+ {
482
+ debug_breakpoint_t *breakpoint;
483
+
484
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
485
+ breakpoint->hit_value = FIX2INT(value);
486
+ return value;
487
+ }
488
+
489
+ /*
490
+ * call-seq:
491
+ * breakpoint.hit_condition -> symbol
492
+ *
493
+ * Returns the hit condition of the breakpoint:
494
+ *
495
+ * +nil+ if it is an unconditional breakpoint, or
496
+ * :greater_or_equal, :equal, :modulo
497
+ */
498
+ static VALUE
499
+ breakpoint_hit_condition(VALUE self)
500
+ {
501
+ debug_breakpoint_t *breakpoint;
502
+
503
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
504
+ switch(breakpoint->hit_condition)
505
+ {
506
+ case HIT_COND_GE:
507
+ return ID2SYM(rb_intern("greater_or_equal"));
508
+ case HIT_COND_EQ:
509
+ return ID2SYM(rb_intern("equal"));
510
+ case HIT_COND_MOD:
511
+ return ID2SYM(rb_intern("modulo"));
512
+ case HIT_COND_NONE:
513
+ default:
514
+ return Qnil;
515
+ }
516
+ }
517
+
518
+ /*
519
+ * call-seq:
520
+ * breakpoint.hit_condition = symbol
521
+ *
522
+ * Sets the hit condition of the breakpoint which must be one of the following values:
523
+ *
524
+ * +nil+ if it is an unconditional breakpoint, or
525
+ * :greater_or_equal(:ge), :equal(:eq), :modulo(:mod)
526
+ */
527
+ static VALUE
528
+ breakpoint_set_hit_condition(VALUE self, VALUE value)
529
+ {
530
+ debug_breakpoint_t *breakpoint;
531
+ ID id_value;
532
+
533
+ Data_Get_Struct(self, debug_breakpoint_t, breakpoint);
534
+ id_value = rb_to_id(value);
535
+
536
+ if(rb_intern("greater_or_equal") == id_value || rb_intern("ge") == id_value)
537
+ breakpoint->hit_condition = HIT_COND_GE;
538
+ else if(rb_intern("equal") == id_value || rb_intern("eq") == id_value)
539
+ breakpoint->hit_condition = HIT_COND_EQ;
540
+ else if(rb_intern("modulo") == id_value || rb_intern("mod") == id_value)
541
+ breakpoint->hit_condition = HIT_COND_MOD;
542
+ else
543
+ rb_raise(rb_eArgError, "Invalid condition parameter");
544
+ return value;
545
+ }
546
+
547
+ /*
548
+ * Document-class: Breakpoint
549
+ *
550
+ * == Summary
551
+ *
552
+ * This class represents a breakpoint. It defines position of the breakpoint and
553
+ * condition when this breakpoint should be triggered.
554
+ */
555
+ void
556
+ Init_breakpoint()
557
+ {
558
+ cBreakpoint = rb_define_class_under(mDebugger, "Breakpoint", rb_cObject);
559
+ rb_define_method(cBreakpoint, "enabled=", breakpoint_set_enabled, 1);
560
+ rb_define_method(cBreakpoint, "enabled?", breakpoint_enabled, 0);
561
+ rb_define_method(cBreakpoint, "expr", breakpoint_expr, 0);
562
+ rb_define_method(cBreakpoint, "expr=", breakpoint_set_expr, 1);
563
+ rb_define_method(cBreakpoint, "hit_condition", breakpoint_hit_condition, 0);
564
+ rb_define_method(cBreakpoint, "hit_condition=", breakpoint_set_hit_condition, 1);
565
+ rb_define_method(cBreakpoint, "hit_count", breakpoint_hit_count, 0);
566
+ rb_define_method(cBreakpoint, "hit_value", breakpoint_hit_value, 0);
567
+ rb_define_method(cBreakpoint, "hit_value=", breakpoint_set_hit_value, 1);
568
+ rb_define_method(cBreakpoint, "id", breakpoint_id, 0);
569
+ rb_define_method(cBreakpoint, "pos", breakpoint_pos, 0);
570
+ rb_define_method(cBreakpoint, "pos=", breakpoint_set_pos, 1);
571
+ rb_define_method(cBreakpoint, "source", breakpoint_source, 0);
572
+ rb_define_method(cBreakpoint, "source=", breakpoint_set_source, 1);
573
+ idEval = rb_intern("eval");
574
+ rdebug_catchpoints = rb_hash_new();
575
+
576
+ }
577
+
578
+