debase 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b4c8f78116379934df37e337705708147ce878c3
4
+ data.tar.gz: 6a037e645748a877e64fd2548025b9d72c2fb698
5
+ SHA512:
6
+ metadata.gz: f35b489310522fe41416655463caceb0c63c527c37e446d79629b6aa8850c00f7787b9a805b2d35ddf25cd1d96de57daa5dabc0fbab00ac1869fa1de9e0f3206
7
+ data.tar.gz: fcaf13c8b8eb973d419a2ead16c8a2c35904685888ea7382be6a9d627538126e5380666955fcd6d09c556fe723a3a991512622be725f5ac7745e6a932b7056d3
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ ext/*.o
6
+ ext/*.bundle
7
+ ext/Makefile
8
+ ext/*.log
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-head
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in debase.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (C) 2005 Kent Sibilev <ksibilev@yahoo.com>
2
+ All rights reserved.
3
+ *
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+ *
13
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
+ ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
+ SUCH DAMAGE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2007-2008, debug-commons team
2
+ Copyright (c) 2012, Dennis Ushakov
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
data/README ADDED
@@ -0,0 +1,22 @@
1
+ = debase
2
+
3
+ == Overview
4
+
5
+ debase is a fast implementation of the standard debugger debug.rb for
6
+ Ruby 2.0.0. The faster execution speed and 2.0.0 compatibility is achieved
7
+ by utilizing a TracePoint mechanism in the Ruby C API.
8
+
9
+ == Requirements
10
+
11
+ debase requires Ruby 2.0.0 or higher.
12
+
13
+ == Install
14
+
15
+ debase is provided as a RubyGem. To install:
16
+
17
+ <tt>gem install debase</tt>
18
+
19
+ == License
20
+
21
+ debase contains parts of the code from ruby-debug-base gem.
22
+ See MIT_LICENSE and LICENSE for license information.
@@ -0,0 +1,34 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ BASE_TEST_FILE_LIST = Dir['test/**/test_*.rb']
5
+
6
+ desc "Remove built files"
7
+ task :clean do
8
+ cd "ext" do
9
+ if File.exists?("Makefile")
10
+ sh "make clean"
11
+ rm "Makefile"
12
+ end
13
+ derived_files = Dir.glob(".o") + Dir.glob("*.so") + Dir.glob("*.bundle")
14
+ rm derived_files unless derived_files.empty?
15
+ end
16
+ end
17
+
18
+ desc "Create the core debase shared library extension"
19
+ task :lib => :clean do
20
+ Dir.chdir("ext") do
21
+ system("#{Gem.ruby} extconf.rb && make")
22
+ exit $?.to_i if $?.to_i != 0
23
+ end
24
+ end
25
+
26
+ desc "Test debase."
27
+ Rake::TestTask.new(:test) do |t|
28
+ t.libs += ['./ext', './lib']
29
+ t.test_files = FileList[BASE_TEST_FILE_LIST]
30
+ t.verbose = true
31
+ end
32
+ task :test => :lib
33
+
34
+ task :default => :test
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "debase/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "debase"
7
+ s.version = Debase::VERSION
8
+ s.authors = ["Dennis Ushakov"]
9
+ s.email = ["dennis.ushakov@gmail.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{debase is a fast implementation of the standard Ruby debugger debug.rb for Ruby 2.0}
12
+ s.description = <<-EOF
13
+ debase is a fast implementation of the standard Ruby debugger debug.rb for Ruby 2.0.
14
+ It is implemented by utilizing a new Ruby TracePoint class. The core component
15
+ provides support that front-ends can build on. It provides breakpoint
16
+ handling, bindings for stack frames among other things.
17
+ EOF
18
+
19
+ s.rubyforge_project = "debase"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+
26
+ s.extensions = ["ext/extconf.rb"]
27
+
28
+ s.add_development_dependency "test-unit"
29
+ s.add_development_dependency "rake"
30
+ end
@@ -0,0 +1,233 @@
1
+ #include <debase_internals.h>
2
+
3
+ #ifdef _WIN32
4
+ #include <ctype.h>
5
+ #endif
6
+
7
+ #if defined DOSISH
8
+ #define isdirsep(x) ((x) == '/' || (x) == '\\')
9
+ #else
10
+ #define isdirsep(x) ((x) == '/')
11
+ #endif
12
+
13
+ static VALUE cBreakpoint;
14
+ static int breakpoint_max;
15
+
16
+ extern VALUE
17
+ catchpoint_hit_count(VALUE catchpoints, VALUE exception, VALUE *exception_name) {
18
+ VALUE ancestors;
19
+ VALUE expn_class;
20
+ VALUE aclass;
21
+ VALUE mod_name;
22
+ VALUE hit_count;
23
+ int i;
24
+
25
+ if (catchpoints == Qnil /*|| st_get_num_entries(RHASH_TBL(rdebug_catchpoints)) == 0)*/)
26
+ return Qnil;
27
+ expn_class = rb_obj_class(exception);
28
+ ancestors = rb_mod_ancestors(expn_class);
29
+ for(i = 0; i < RARRAY_LEN(ancestors); i++)
30
+ {
31
+ aclass = rb_ary_entry(ancestors, i);
32
+ mod_name = rb_mod_name(aclass);
33
+ hit_count = rb_hash_aref(catchpoints, mod_name);
34
+ if(hit_count != Qnil)
35
+ {
36
+ *exception_name = mod_name;
37
+ return hit_count;
38
+ }
39
+ }
40
+ return Qnil;
41
+ }
42
+
43
+ static void
44
+ Breakpoint_mark(breakpoint_t *breakpoint)
45
+ {
46
+ rb_gc_mark(breakpoint->source);
47
+ rb_gc_mark(breakpoint->expr);
48
+ }
49
+
50
+ static VALUE
51
+ Breakpoint_create(VALUE klass)
52
+ {
53
+ breakpoint_t *breakpoint;
54
+
55
+ breakpoint = ALLOC(breakpoint_t);
56
+ return Data_Wrap_Struct(klass, Breakpoint_mark, xfree, breakpoint);
57
+ }
58
+
59
+ static VALUE
60
+ Breakpoint_initialize(VALUE self, VALUE source, VALUE pos, VALUE expr)
61
+ {
62
+ breakpoint_t *breakpoint;
63
+
64
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
65
+ breakpoint->id = ++breakpoint_max;
66
+ breakpoint->source = StringValue(source);
67
+ breakpoint->line = FIX2INT(pos);
68
+ breakpoint->enabled = Qtrue;
69
+ breakpoint->expr = NIL_P(expr) ? expr : StringValue(expr);
70
+
71
+ return Qnil;
72
+ }
73
+
74
+ static VALUE
75
+ Breakpoint_remove(VALUE self, VALUE breakpoints, VALUE id_value)
76
+ {
77
+ int i;
78
+ int id;
79
+ VALUE breakpoint_object;
80
+ breakpoint_t *breakpoint;
81
+
82
+ if (breakpoints == Qnil) return Qnil;
83
+
84
+ id = FIX2INT(id_value);
85
+
86
+ for(i = 0; i < RARRAY_LEN(breakpoints); i++)
87
+ {
88
+ breakpoint_object = rb_ary_entry(breakpoints, i);
89
+ Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
90
+ if(breakpoint->id == id)
91
+ {
92
+ rb_ary_delete_at(breakpoints, i);
93
+ return breakpoint_object;
94
+ }
95
+ }
96
+ return Qnil;
97
+ }
98
+
99
+ static VALUE
100
+ Breakpoint_id(VALUE self)
101
+ {
102
+ breakpoint_t *breakpoint;
103
+
104
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
105
+ return INT2FIX(breakpoint->id);
106
+ }
107
+
108
+ static VALUE
109
+ Breakpoint_source(VALUE self)
110
+ {
111
+ breakpoint_t *breakpoint;
112
+
113
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
114
+ return breakpoint->source;
115
+ }
116
+
117
+ static VALUE
118
+ Breakpoint_pos(VALUE self)
119
+ {
120
+ breakpoint_t *breakpoint;
121
+
122
+ Data_Get_Struct(self, breakpoint_t, breakpoint);
123
+ return INT2FIX(breakpoint->line);
124
+ }
125
+
126
+ int
127
+ filename_cmp_impl(VALUE source, char *file)
128
+ {
129
+ char *source_ptr, *file_ptr;
130
+ long s_len, f_len, min_len;
131
+ long s,f;
132
+ int dirsep_flag = 0;
133
+
134
+ s_len = RSTRING_LEN(source);
135
+ f_len = strlen(file);
136
+ min_len = s_len < f_len ? s_len : f_len;
137
+
138
+ source_ptr = RSTRING_PTR(source);
139
+ file_ptr = file;
140
+
141
+ for( s = s_len - 1, f = f_len - 1; s >= s_len - min_len && f >= f_len - min_len; s--, f-- )
142
+ {
143
+ if((source_ptr[s] == '.' || file_ptr[f] == '.') && dirsep_flag)
144
+ return 1;
145
+ if(isdirsep(source_ptr[s]) && isdirsep(file_ptr[f]))
146
+ dirsep_flag = 1;
147
+ #ifdef DOSISH_DRIVE_LETTER
148
+ else if (s == 0)
149
+ return(toupper(source_ptr[s]) == toupper(file_ptr[f]));
150
+ #endif
151
+ else if(source_ptr[s] != file_ptr[f])
152
+ return 0;
153
+ }
154
+ return 1;
155
+ }
156
+
157
+ int
158
+ filename_cmp(VALUE source, char *file)
159
+ {
160
+ #ifdef _WIN32
161
+ return filename_cmp_impl(source, file);
162
+ #else
163
+ #ifdef PATH_MAX
164
+ char path[PATH_MAX + 1];
165
+ path[PATH_MAX] = 0;
166
+ return filename_cmp_impl(source, realpath(file, path) != NULL ? path : file);
167
+ #else
168
+ char *path;
169
+ int result;
170
+ path = realpath(file, NULL);
171
+ result = filename_cmp_impl(source, path == NULL ? file : path);
172
+ free(path);
173
+ return result;
174
+ #endif
175
+ #endif
176
+ }
177
+
178
+ static int
179
+ check_breakpoint_by_pos(VALUE breakpoint_object, char *file, int line)
180
+ {
181
+ breakpoint_t *breakpoint;
182
+
183
+ if(breakpoint_object == Qnil)
184
+ return 0;
185
+ Data_Get_Struct(breakpoint_object, breakpoint_t, breakpoint);
186
+ if (Qtrue != breakpoint->enabled) return 0;
187
+ if(breakpoint->line != line)
188
+ return 0;
189
+ if(filename_cmp(breakpoint->source, file))
190
+ return 1;
191
+ return 0;
192
+ }
193
+
194
+ static VALUE
195
+ Breakpoint_find(VALUE self, VALUE breakpoints, VALUE source, VALUE pos, VALUE binding)
196
+ {
197
+ return breakpoint_find(breakpoints, source, pos, binding);
198
+ }
199
+
200
+ extern VALUE
201
+ breakpoint_find(VALUE breakpoints, VALUE source, VALUE pos, VALUE binding)
202
+ {
203
+ VALUE breakpoint_object;
204
+ char *file;
205
+ int line;
206
+ int i;
207
+
208
+ file = RSTRING_PTR(source);
209
+ line = FIX2INT(pos);
210
+ for(i = 0; i < RARRAY_LEN(breakpoints); i++)
211
+ {
212
+ breakpoint_object = rb_ary_entry(breakpoints, i);
213
+ if (check_breakpoint_by_pos(breakpoint_object, file, line))
214
+ {
215
+ return breakpoint_object;
216
+ }
217
+ }
218
+ return Qnil;
219
+ }
220
+
221
+ extern void
222
+ Init_breakpoint(VALUE mDebase)
223
+ {
224
+ breakpoint_max = 0;
225
+ cBreakpoint = rb_define_class_under(mDebase, "Breakpoint", rb_cObject);
226
+ rb_define_singleton_method(cBreakpoint, "find", Breakpoint_find, 4);
227
+ rb_define_singleton_method(cBreakpoint, "remove", Breakpoint_remove, 2);
228
+ rb_define_method(cBreakpoint, "initialize", Breakpoint_initialize, 3);
229
+ rb_define_method(cBreakpoint, "id", Breakpoint_id, 0);
230
+ rb_define_method(cBreakpoint, "source", Breakpoint_source, 0);
231
+ rb_define_method(cBreakpoint, "pos", Breakpoint_pos, 0);
232
+ rb_define_alloc_func(cBreakpoint, Breakpoint_create);
233
+ }
@@ -0,0 +1,377 @@
1
+ #include <debase_internals.h>
2
+
3
+ static VALUE cContext;
4
+ static int thnum_current = 0;
5
+
6
+ static VALUE idAlive;
7
+
8
+ /* "Step", "Next" and "Finish" do their work by saving information
9
+ about where to stop next. reset_stopping_points removes/resets this
10
+ information. */
11
+ extern void
12
+ reset_stepping_stop_points(debug_context_t *context)
13
+ {
14
+ context->dest_frame = -1;
15
+ context->stop_line = -1;
16
+ context->stop_next = -1;
17
+ }
18
+
19
+ static inline VALUE
20
+ Context_thnum(VALUE self) {
21
+ debug_context_t *context;
22
+ Data_Get_Struct(self, debug_context_t, context);
23
+ return INT2FIX(context->thnum);
24
+ }
25
+
26
+ static inline void
27
+ delete_frame(debug_context_t *context)
28
+ {
29
+ debug_frame_t *frame;
30
+
31
+ frame = context->stack;
32
+ context->stack = frame->prev;
33
+ context->stack_size--;
34
+ xfree(frame);
35
+ }
36
+
37
+ static inline void
38
+ fill_frame(debug_frame_t *frame, char* file, int line, VALUE binding, VALUE self)
39
+ {
40
+ frame->file = file;
41
+ frame->line = line;
42
+ frame->binding = binding;
43
+ frame->self = self;
44
+ }
45
+
46
+ static inline VALUE
47
+ Context_stack_size(VALUE self)
48
+ {
49
+ debug_context_t *context;
50
+ Data_Get_Struct(self, debug_context_t, context);
51
+ return INT2FIX(context->stack_size);
52
+ }
53
+
54
+ static inline VALUE
55
+ Context_thread(VALUE self)
56
+ {
57
+ debug_context_t *context;
58
+ Data_Get_Struct(self, debug_context_t, context);
59
+ return context->thread;
60
+ }
61
+
62
+ static inline VALUE
63
+ Context_dead(VALUE self)
64
+ {
65
+ debug_context_t *context;
66
+ Data_Get_Struct(self, debug_context_t, context);
67
+ return IS_THREAD_ALIVE(context->thread) ? Qfalse : Qtrue;
68
+ }
69
+
70
+ extern VALUE
71
+ Context_ignored(VALUE self)
72
+ {
73
+ debug_context_t *context;
74
+
75
+ if (self == Qnil) return Qtrue;
76
+ Data_Get_Struct(self, debug_context_t, context);
77
+ return CTX_FL_TEST(context, CTX_FL_IGNORE) ? Qtrue : Qfalse;
78
+ }
79
+
80
+ extern void
81
+ push_frame(VALUE context_object, char* file, int line, VALUE binding, VALUE self)
82
+ {
83
+ debug_context_t *context;
84
+ debug_frame_t *frame;
85
+ Data_Get_Struct(context_object, debug_context_t, context);
86
+
87
+ frame = ALLOC(debug_frame_t);
88
+ fill_frame(frame, file, line, binding, self);
89
+ frame->prev = context->stack;
90
+ context->stack = frame;
91
+ context->stack_size++;
92
+ }
93
+
94
+ extern void
95
+ pop_frame(VALUE context_object)
96
+ {
97
+ debug_context_t *context;
98
+ Data_Get_Struct(context_object, debug_context_t, context);
99
+
100
+ if (context->stack_size > 0) {
101
+ delete_frame(context);
102
+ }
103
+ }
104
+
105
+ extern void
106
+ update_frame(VALUE context_object, char* file, int line, VALUE binding, VALUE self)
107
+ {
108
+ debug_context_t *context;
109
+ Data_Get_Struct(context_object, debug_context_t, context);
110
+
111
+ if (context->stack_size == 0) {
112
+ push_frame(context_object, file, line, binding, self);
113
+ return;
114
+ }
115
+ fill_frame(context->stack, file, line, binding, self);
116
+ }
117
+
118
+ static void
119
+ Context_mark(debug_context_t *context)
120
+ {
121
+ debug_frame_t *frame;
122
+
123
+ rb_gc_mark(context->thread);
124
+ frame = context->stack;
125
+ while (frame != NULL) {
126
+ rb_gc_mark(frame->self);
127
+ rb_gc_mark(frame->binding);
128
+ frame = frame->prev;
129
+ }
130
+ }
131
+
132
+ static void
133
+ Context_free(debug_context_t *context) {
134
+ while(context->stack_size > 0) {
135
+ delete_frame(context);
136
+ }
137
+ xfree(context);
138
+ }
139
+
140
+ extern VALUE
141
+ context_create(VALUE thread, VALUE cDebugThread) {
142
+ debug_context_t *context;
143
+
144
+ context = ALLOC(debug_context_t);
145
+ context->stack_size = 0;
146
+ context->stack = NULL;
147
+ context->thnum = ++thnum_current;
148
+ context->thread = thread;
149
+ context->flags = 0;
150
+ context->last_file = NULL;
151
+ context->last_line = -1;
152
+ context->stop_frame = -1;
153
+ reset_stepping_stop_points(context);
154
+ if(rb_obj_class(thread) == cDebugThread) CTX_FL_SET(context, CTX_FL_IGNORE);
155
+ return Data_Wrap_Struct(cContext, Context_mark, Context_free, context);
156
+ }
157
+
158
+ static inline void
159
+ check_frame_number_valid(debug_context_t *context, int frame_no)
160
+ {
161
+ if (frame_no < 0 || frame_no >= context->stack_size) {
162
+ rb_raise(rb_eArgError, "Invalid frame number %d, stack (0...%d)",
163
+ frame_no, context->stack_size);
164
+ }
165
+ }
166
+
167
+ static debug_frame_t*
168
+ get_frame_no(debug_context_t *context, int frame_n)
169
+ {
170
+ debug_frame_t *frame;
171
+ int i;
172
+
173
+ check_frame_number_valid(context, frame_n);
174
+ frame = context->stack;
175
+ for (i = 0; i < frame_n; i++) {
176
+ frame = frame->prev;
177
+ }
178
+ return frame;
179
+ }
180
+
181
+ static VALUE
182
+ Context_frame_file(int argc, VALUE *argv, VALUE self)
183
+ {
184
+ debug_context_t *context;
185
+ debug_frame_t *frame;
186
+ VALUE frame_no;
187
+ int frame_n;
188
+
189
+ Data_Get_Struct(self, debug_context_t, context);
190
+ frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
191
+ frame = get_frame_no(context, frame_n);
192
+ return rb_str_new2(frame->file);
193
+ }
194
+
195
+ static VALUE
196
+ Context_frame_line(int argc, VALUE *argv, VALUE self)
197
+ {
198
+ debug_context_t *context;
199
+ debug_frame_t *frame;
200
+ VALUE frame_no;
201
+ int frame_n;
202
+
203
+ Data_Get_Struct(self, debug_context_t, context);
204
+ frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
205
+ frame = get_frame_no(context, frame_n);
206
+ return INT2FIX(frame->line);
207
+ }
208
+
209
+ static VALUE
210
+ Context_frame_binding(int argc, VALUE *argv, VALUE self)
211
+ {
212
+ debug_context_t *context;
213
+ debug_frame_t *frame;
214
+ VALUE frame_no;
215
+ int frame_n;
216
+
217
+ Data_Get_Struct(self, debug_context_t, context);
218
+ frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
219
+ frame = get_frame_no(context, frame_n);
220
+ return frame->binding;
221
+ }
222
+
223
+ static VALUE
224
+ Context_frame_self(int argc, VALUE *argv, VALUE self)
225
+ {
226
+ debug_context_t *context;
227
+ debug_frame_t *frame;
228
+ VALUE frame_no;
229
+ int frame_n;
230
+
231
+ Data_Get_Struct(self, debug_context_t, context);
232
+ frame_n = rb_scan_args(argc, argv, "01", &frame_no) == 0 ? 0 : FIX2INT(frame_no);
233
+ frame = get_frame_no(context, frame_n);
234
+ return frame->self;
235
+ }
236
+
237
+ static VALUE
238
+ Context_stop_reason(VALUE self)
239
+ {
240
+ debug_context_t *context;
241
+ const char *symbol;
242
+
243
+ Data_Get_Struct(self, debug_context_t, context);
244
+
245
+ switch(context->stop_reason)
246
+ {
247
+ case CTX_STOP_STEP:
248
+ symbol = "step";
249
+ break;
250
+ case CTX_STOP_BREAKPOINT:
251
+ symbol = "breakpoint";
252
+ break;
253
+ case CTX_STOP_CATCHPOINT:
254
+ symbol = "catchpoint";
255
+ break;
256
+ case CTX_STOP_NONE:
257
+ default:
258
+ symbol = "none";
259
+ }
260
+ if(CTX_FL_TEST(context, CTX_FL_DEAD))
261
+ symbol = "post-mortem";
262
+
263
+ return ID2SYM(rb_intern(symbol));
264
+ }
265
+
266
+ static VALUE
267
+ Context_stop_next(int argc, VALUE *argv, VALUE self)
268
+ {
269
+ VALUE steps;
270
+ VALUE force;
271
+ debug_context_t *context;
272
+
273
+ rb_scan_args(argc, argv, "11", &steps, &force);
274
+ if(FIX2INT(steps) < 0) rb_raise(rb_eRuntimeError, "Steps argument can't be negative.");
275
+
276
+ Data_Get_Struct(self, debug_context_t, context);
277
+ context->stop_next = FIX2INT(steps);
278
+ if(RTEST(force))
279
+ CTX_FL_SET(context, CTX_FL_FORCE_MOVE);
280
+ else
281
+ CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
282
+
283
+ return steps;
284
+ }
285
+
286
+ static VALUE
287
+ Context_step_over(int argc, VALUE *argv, VALUE self)
288
+ {
289
+ VALUE lines, frame, force;
290
+ debug_context_t *context;
291
+
292
+ Data_Get_Struct(self, debug_context_t, context);
293
+ if(context->stack_size == 0)
294
+ rb_raise(rb_eRuntimeError, "No frames collected.");
295
+
296
+ rb_scan_args(argc, argv, "12", &lines, &frame, &force);
297
+ context->stop_line = FIX2INT(lines);
298
+ CTX_FL_UNSET(context, CTX_FL_STEPPED);
299
+ if(frame == Qnil)
300
+ {
301
+ context->dest_frame = context->stack_size;
302
+ }
303
+ else
304
+ {
305
+ if(FIX2INT(frame) < 0 && FIX2INT(frame) >= context->stack_size)
306
+ rb_raise(rb_eRuntimeError, "Destination frame is out of range.");
307
+ context->dest_frame = context->stack_size - FIX2INT(frame);
308
+ }
309
+ if(RTEST(force))
310
+ CTX_FL_SET(context, CTX_FL_FORCE_MOVE);
311
+ else
312
+ CTX_FL_UNSET(context, CTX_FL_FORCE_MOVE);
313
+
314
+ return Qnil;
315
+ }
316
+
317
+ static VALUE
318
+ Context_stop_frame(VALUE self, VALUE frame)
319
+ {
320
+ debug_context_t *debug_context;
321
+
322
+ Data_Get_Struct(self, debug_context_t, debug_context);
323
+ if(FIX2INT(frame) < 0 && FIX2INT(frame) >= debug_context->stack_size)
324
+ rb_raise(rb_eRuntimeError, "Stop frame is out of range.");
325
+ debug_context->stop_frame = debug_context->stack_size - FIX2INT(frame);
326
+
327
+ return frame;
328
+ }
329
+
330
+ /*
331
+ * Document-class: Context
332
+ *
333
+ * == Summary
334
+ *
335
+ * Debugger keeps a single instance of this class for each Ruby thread.
336
+ */
337
+ VALUE
338
+ Init_context(VALUE mDebase)
339
+ {
340
+ cContext = rb_define_class_under(mDebase, "Context", rb_cObject);
341
+ rb_define_method(cContext, "stack_size", Context_stack_size, 0);
342
+ rb_define_method(cContext, "thread", Context_thread, 0);
343
+ rb_define_method(cContext, "dead?", Context_dead, 0);
344
+ rb_define_method(cContext, "ignored?", Context_ignored, 0);
345
+ rb_define_method(cContext, "thnum", Context_thnum, 0);
346
+ rb_define_method(cContext, "stop_reason", Context_stop_reason, 0);
347
+ rb_define_method(cContext, "frame_file", Context_frame_file, -1);
348
+ rb_define_method(cContext, "frame_line", Context_frame_line, -1);
349
+ rb_define_method(cContext, "frame_binding", Context_frame_binding, -1);
350
+ rb_define_method(cContext, "frame_self", Context_frame_self, -1);
351
+ rb_define_method(cContext, "stop_next=", Context_stop_next, -1);
352
+ rb_define_method(cContext, "step", Context_stop_next, -1);
353
+ rb_define_method(cContext, "step_over", Context_step_over, -1);
354
+ rb_define_method(cContext, "stop_frame=", Context_stop_frame, 1);
355
+
356
+ idAlive = rb_intern("alive?");
357
+
358
+ return cContext;
359
+ // rb_define_method(cContext, "suspend", context_suspend, 0);
360
+ // rb_define_method(cContext, "suspended?", context_is_suspended, 0);
361
+ // rb_define_method(cContext, "resume", context_resume, 0);
362
+ // rb_define_method(cContext, "tracing", context_tracing, 0);
363
+ // rb_define_method(cContext, "tracing=", context_set_tracing, 1);
364
+ // rb_define_method(cContext, "ignored?", context_ignored, 0);
365
+ // rb_define_method(cContext, "frame_args", context_frame_args, -1);
366
+ // rb_define_method(cContext, "frame_args_info", context_frame_args_info, -1);
367
+ // rb_define_method(cContext, "frame_class", context_frame_class, -1);
368
+ // rb_define_method(cContext, "frame_id", context_frame_id, -1);
369
+ // rb_define_method(cContext, "frame_locals", context_frame_locals, -1);
370
+ // rb_define_method(cContext, "frame_method", context_frame_id, -1);
371
+ // rb_define_method(cContext, "breakpoint",
372
+ // context_breakpoint, 0); /* in breakpoint.c */
373
+ // rb_define_method(cContext, "set_breakpoint",
374
+ // context_set_breakpoint, -1); /* in breakpoint.c */
375
+ // rb_define_method(cContext, "jump", context_jump, 2);
376
+ // rb_define_method(cContext, "pause", context_pause, 0);
377
+ }