ruby-debug 0.6.1-mswin32 → 0.6.2-mswin32

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1,6 @@
1
+ Author and maintainer:
2
+ Kent Sibilev
3
+
4
+ Contributers:
5
+ Markus Barchfeld
6
+ R. Bernstein
data/CHANGES CHANGED
@@ -1,3 +1,8 @@
1
+ 0.6.2
2
+ - Added thread lookup cache.
3
+ - Control thread is always started by rdebug script.
4
+ - Ability to specify negative frame number to frame commands. Patch from R. Bernstein.
5
+
1
6
  0.6.1
2
7
  - Another performance optimization.
3
8
 
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ FILES = FileList[
12
12
  'README',
13
13
  'LICENSE',
14
14
  'CHANGES',
15
+ 'AUTHORS',
15
16
  'lib/**/*',
16
17
  'ext/*',
17
18
  'doc/*',
data/bin/rdebug CHANGED
@@ -27,14 +27,15 @@ EOB
27
27
  opts.separator ""
28
28
  opts.separator "Options:"
29
29
  opts.on("-s", "--server", "Listen for remote connections") {options.server = true}
30
+ opts.on("-w", "--wait", "Wait for a client connection, implies -s option") {options.wait = true}
30
31
  opts.on("-c", "--client", "Connect to remote debugger") {options.client = true}
31
32
  opts.on("-h", "--host HOST", "Host name used for remote debugging") {|options.host|}
32
- opts.on("-w", "--wait", "Wait for a client connection, implies -s option") {options.wait = true}
33
+ opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
34
+ opts.on("--cport PORT", Integer, "Port used for contol commands, implies -s option") {|options.port|}
33
35
  opts.on("-x", "--trace", "turn on line tracing") {options.tracing = true}
34
36
  opts.on("-n", "--nostop", "Do not stop when stript is loaded") {options.nostop = true}
35
37
  opts.on("-f", "--keep-frame-info", "Keep frame info") {options.frame_info = true}
36
38
  opts.on("-m", "--post-mortem", "Activate post-mortem mode") {options.post_mortem = true}
37
- opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") {|options.port|}
38
39
  opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") do |path|
39
40
  $LOAD_PATH.unshift(path)
40
41
  end
@@ -44,7 +45,6 @@ EOB
44
45
  exit
45
46
  end
46
47
  end
47
- opts.on("--cport PORT", Integer, "Port used for contol commands, implies -s option") {|options.port|}
48
48
  opts.separator ""
49
49
  opts.separator "Common options:"
50
50
  opts.on_tail("--help", "Show this message") do
@@ -82,26 +82,43 @@ else
82
82
  exit(-1)
83
83
  end
84
84
 
85
+ # save script name
85
86
  Debugger::PROG_SCRIPT = ARGV.shift
87
+
88
+ # install interruption handler
86
89
  trap('INT') { Debugger.interrupt_last }
90
+
91
+ # set options
87
92
  Debugger.stop_on_connect = !options.nostop
88
93
  Debugger.wait_connection = options.wait
89
94
  Debugger.keep_frame_info = options.frame_info
95
+
96
+ # load user script
90
97
  load "#{ENV["HOME"]}/.rdebugrc" if File.exists?("#{ENV["HOME"]}/.rdebugrc")
98
+
91
99
  if options.server
100
+ # start remote mode
92
101
  Debugger.start_remote(options.host, [options.port, options.cport], options.post_mortem)
102
+ # load script
93
103
  Debugger.debug_load Debugger::PROG_SCRIPT
94
104
  else
105
+ # activate debugger
95
106
  Debugger.start
107
+ # start control thread
108
+ Debugger.start_control(options.host, options.cport)
109
+
110
+ # run startup script if specified
96
111
  if options.script
97
112
  Debugger.run_script(options.script)
98
113
  end
114
+ # activate post-mortem
99
115
  Debugger.post_mortem if options.post_mortem
100
116
  if options.tracing
101
117
  Debugger.tracing = true
102
118
  else
103
119
  debugger 2 unless options.nostop
104
120
  end
121
+ # load script
105
122
  Debugger.debug_load Debugger::PROG_SCRIPT
106
123
  end
107
124
  end
data/ext/ruby_debug.c CHANGED
@@ -4,7 +4,7 @@
4
4
  #include <rubysig.h>
5
5
  #include <st.h>
6
6
 
7
- #define DEBUG_VERSION "0.6.1"
7
+ #define DEBUG_VERSION "0.6.2"
8
8
 
9
9
  #define CTX_FL_MOVED (1<<1)
10
10
  #define CTX_FL_SUSPEND (1<<2)
@@ -26,6 +26,13 @@
26
26
  #define min(x,y) ((x) < (y) ? (x) : (y))
27
27
  #endif
28
28
 
29
+ typedef struct {
30
+ ID id;
31
+ VALUE binding;
32
+ int line;
33
+ const char * file;
34
+ } debug_frame_t;
35
+
29
36
  typedef struct {
30
37
  int thnum;
31
38
  int flags;
@@ -35,17 +42,11 @@ typedef struct {
35
42
  int stop_frame;
36
43
  unsigned long thread_id;
37
44
  VALUE frames;
45
+ debug_frame_t *top_frame;
38
46
  const char * last_file;
39
47
  int last_line;
40
48
  } debug_context_t;
41
49
 
42
- typedef struct {
43
- ID id;
44
- VALUE binding;
45
- int line;
46
- const char * file;
47
- } debug_frame_t;
48
-
49
50
  enum bp_type {BP_POS_TYPE, BP_METHOD_TYPE};
50
51
 
51
52
  typedef struct {
@@ -72,6 +73,10 @@ static VALUE locker = Qnil;
72
73
  static VALUE post_mortem = Qfalse;
73
74
  static VALUE keep_frame_info = Qfalse;
74
75
 
76
+ static VALUE last_context = Qnil;
77
+ static VALUE last_thread = Qnil;
78
+ static debug_context_t *last_debug_context = NULL;
79
+
75
80
  static VALUE mDebugger;
76
81
  static VALUE cThreadsTable;
77
82
  static VALUE cContext;
@@ -86,8 +91,6 @@ static ID idAtCatchpoint;
86
91
  static ID idAtTracing;
87
92
  static ID idEval;
88
93
  static ID idList;
89
- static ID idClear;
90
- static ID idIndex;
91
94
 
92
95
  static int start_count = 0;
93
96
  static int thnum_max = 0;
@@ -130,7 +133,7 @@ id2ref_unprotected(VALUE id)
130
133
  static id2ref_func_t f_id2ref = NULL;
131
134
  if(f_id2ref == NULL)
132
135
  {
133
- f_id2ref = ruby_method_ptr(rb_mObjectSpace, rb_intern("_id2ref"));
136
+ f_id2ref = (id2ref_func_t)ruby_method_ptr(rb_mObjectSpace, rb_intern("_id2ref"));
134
137
  }
135
138
  return f_id2ref(rb_mObjectSpace, id);
136
139
  }
@@ -204,25 +207,6 @@ remove_from_locked()
204
207
  return thread;
205
208
  }
206
209
 
207
- static int
208
- thread_hash(unsigned long thread_id)
209
- {
210
- return (int)thread_id;
211
- }
212
-
213
- static int
214
- thread_cmp(VALUE a, VALUE b)
215
- {
216
- if(a == b) return 0;
217
- if(a < b) return -1;
218
- return 1;
219
- }
220
-
221
- static struct st_hash_type st_thread_hash = {
222
- thread_cmp,
223
- thread_hash
224
- };
225
-
226
210
  static int
227
211
  threads_table_mark_keyvalue(VALUE key, VALUE value, int dummy)
228
212
  {
@@ -251,7 +235,7 @@ threads_table_create()
251
235
  threads_table_t *threads_table;
252
236
 
253
237
  threads_table = ALLOC(threads_table_t);
254
- threads_table->tbl = st_init_table(&st_thread_hash);
238
+ threads_table->tbl = st_init_numtable();
255
239
  return Data_Wrap_Struct(cThreadsTable, threads_table_mark, threads_table_free, threads_table);
256
240
  }
257
241
 
@@ -273,12 +257,13 @@ threads_table_clear(VALUE table)
273
257
  static VALUE
274
258
  is_thread_alive(VALUE thread)
275
259
  {
276
- static ID id_alive = 0;
277
- if(!id_alive)
260
+ typedef VALUE (*thread_alive_func_t)(VALUE);
261
+ static thread_alive_func_t f_thread_alive = NULL;
262
+ if(!f_thread_alive)
278
263
  {
279
- id_alive = rb_intern("alive?");
264
+ f_thread_alive = (thread_alive_func_t)ruby_method_ptr(rb_cThread, rb_intern("alive?"));
280
265
  }
281
- return rb_funcall(thread, id_alive, 0);
266
+ return f_thread_alive(thread);
282
267
  }
283
268
 
284
269
  static int
@@ -353,27 +338,43 @@ debug_context_create(VALUE thread)
353
338
  debug_context->stop_line = -1;
354
339
  debug_context->stop_frame = -1;
355
340
  debug_context->frames = rb_ary_new();
341
+ debug_context->top_frame = NULL;
356
342
  debug_context->thread_id = ref2id(thread);
357
343
  result = Data_Wrap_Struct(cContext, debug_context_mark, xfree, debug_context);
358
344
  return result;
359
345
  }
360
346
 
361
- static VALUE
362
- thread_context_lookup(VALUE thread)
347
+ static void
348
+ thread_context_lookup(VALUE thread, VALUE *context, debug_context_t **debug_context)
363
349
  {
364
- VALUE context;
365
350
  threads_table_t *threads_table;
366
- unsigned long thread_id = ref2id(thread);
351
+ unsigned long thread_id;
352
+ debug_context_t *l_debug_context;
367
353
 
368
354
  debug_check_started();
369
355
 
356
+ if(last_thread == thread && last_context != Qnil)
357
+ {
358
+ *context = last_context;
359
+ if(debug_context)
360
+ *debug_context = last_debug_context;
361
+ return;
362
+ }
363
+ thread_id = ref2id(thread);
370
364
  Data_Get_Struct(threads_tbl, threads_table_t, threads_table);
371
- if(!st_lookup(threads_table->tbl, thread_id, &context))
365
+ if(!st_lookup(threads_table->tbl, thread_id, context))
372
366
  {
373
- context = debug_context_create(thread);
374
- st_insert(threads_table->tbl, thread_id, context);
367
+ *context = debug_context_create(thread);
368
+ st_insert(threads_table->tbl, thread_id, *context);
375
369
  }
376
- return context;
370
+
371
+ Data_Get_Struct(*context, debug_context_t, l_debug_context);
372
+ if(debug_context)
373
+ *debug_context = l_debug_context;
374
+
375
+ last_thread = thread;
376
+ last_context = *context;
377
+ last_debug_context = l_debug_context;
377
378
  }
378
379
 
379
380
  static void
@@ -383,22 +384,6 @@ debug_frame_mark(void *data)
383
384
  rb_gc_mark(debug_frame->binding);
384
385
  }
385
386
 
386
- static VALUE
387
- debug_frame_create(char *file, int line, VALUE binding, ID id)
388
- {
389
- VALUE result;
390
- debug_frame_t *debug_frame;
391
-
392
- debug_frame = ALLOC(debug_frame_t);
393
- debug_frame->file = file;
394
- debug_frame->line = line;
395
- debug_frame->binding = binding;
396
- debug_frame->id = id;
397
- result = Data_Wrap_Struct(cFrame, debug_frame_mark, xfree, debug_frame);
398
-
399
- return result;
400
- }
401
-
402
387
  static VALUE
403
388
  call_at_line_unprotected(VALUE args)
404
389
  {
@@ -423,9 +408,17 @@ static void
423
408
  save_call_frame(VALUE self, char *file, int line, ID mid, debug_context_t *debug_context)
424
409
  {
425
410
  VALUE frame, binding;
411
+ debug_frame_t *debug_frame;
426
412
 
427
413
  binding = self && RTEST(keep_frame_info)? create_binding(self) : Qnil;
428
- frame = debug_frame_create(file, line, binding, mid);
414
+ debug_frame = ALLOC(debug_frame_t);
415
+ debug_frame->file = file;
416
+ debug_frame->line = line;
417
+ debug_frame->binding = binding;
418
+ debug_frame->id = mid;
419
+ frame = Data_Wrap_Struct(cFrame, debug_frame_mark, xfree, debug_frame);
420
+
421
+ debug_context->top_frame = debug_frame;
429
422
  rb_ary_push(debug_context->frames, frame);
430
423
  }
431
424
 
@@ -570,9 +563,16 @@ get_top_frame(debug_context_t *debug_context)
570
563
  debug_frame_t *debug_frame;
571
564
  if(RARRAY(debug_context->frames)->len == 0)
572
565
  return NULL;
573
- else {
574
- frame = RARRAY(debug_context->frames)->ptr[RARRAY(debug_context->frames)->len-1];
575
- Data_Get_Struct(frame, debug_frame_t, debug_frame);
566
+ else
567
+ {
568
+ if(debug_context->top_frame == NULL)
569
+ {
570
+ frame = RARRAY(debug_context->frames)->ptr[RARRAY(debug_context->frames)->len-1];
571
+ Data_Get_Struct(frame, debug_frame_t, debug_frame);
572
+ debug_context->top_frame = debug_frame;
573
+ }
574
+ else
575
+ debug_frame = debug_context->top_frame;
576
576
  return debug_frame;
577
577
  }
578
578
  }
@@ -626,8 +626,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
626
626
  if(!node) return;
627
627
 
628
628
  thread = rb_thread_current();
629
- context = thread_context_lookup(thread);
630
- Data_Get_Struct(context, debug_context_t, debug_context);
629
+ thread_context_lookup(thread, &context, &debug_context);
631
630
 
632
631
  /* return if thread is marked as 'ignored'.
633
632
  debugger's threads are marked this way
@@ -753,6 +752,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
753
752
  debug_context->stop_frame = 0;
754
753
  }
755
754
  rb_ary_pop(debug_context->frames);
755
+ debug_context->top_frame = NULL;
756
756
  break;
757
757
  }
758
758
  case RUBY_EVENT_CLASS:
@@ -811,7 +811,7 @@ debug_event_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
811
811
  cleanup:
812
812
 
813
813
  /* check that all contexts point to alive threads */
814
- if(hook_count - last_check > 1000)
814
+ if(hook_count - last_check > 3000)
815
815
  {
816
816
  check_thread_contexts();
817
817
  last_check = hook_count;
@@ -1077,8 +1077,24 @@ debug_current_context(VALUE self)
1077
1077
  debug_check_started();
1078
1078
 
1079
1079
  thread = rb_thread_current();
1080
- context = thread_context_lookup(thread);
1080
+ thread_context_lookup(thread, &context, NULL);
1081
+
1082
+ return context;
1083
+ }
1081
1084
 
1085
+ /*
1086
+ * call-seq:
1087
+ * Debugger.thread_context(thread) -> context
1088
+ *
1089
+ * Returns context of the thread passed as an argument.
1090
+ */
1091
+ static VALUE
1092
+ debug_thread_context(VALUE self, VALUE thread)
1093
+ {
1094
+ VALUE context;
1095
+
1096
+ debug_check_started();
1097
+ thread_context_lookup(thread, &context, NULL);
1082
1098
  return context;
1083
1099
  }
1084
1100
 
@@ -1105,7 +1121,7 @@ debug_contexts(VALUE self)
1105
1121
  for(i = 0; i < RARRAY(list)->len; i++)
1106
1122
  {
1107
1123
  thread = rb_ary_entry(list, i);
1108
- context = thread_context_lookup(thread);
1124
+ thread_context_lookup(thread, &context, NULL);
1109
1125
  rb_ary_push(new_list, context);
1110
1126
  }
1111
1127
  threads_table_clear(threads_tbl);
@@ -1140,7 +1156,7 @@ debug_suspend(VALUE self)
1140
1156
  saved_crit = rb_thread_critical;
1141
1157
  rb_thread_critical = Qtrue;
1142
1158
  context_list = debug_contexts(self);
1143
- current = thread_context_lookup(rb_thread_current());
1159
+ thread_context_lookup(rb_thread_current(), &current, NULL);
1144
1160
 
1145
1161
  for(i = 0; i < RARRAY(context_list)->len; i++)
1146
1162
  {
@@ -1179,7 +1195,7 @@ debug_resume(VALUE self)
1179
1195
  rb_thread_critical = Qtrue;
1180
1196
  context_list = debug_contexts(self);
1181
1197
 
1182
- current = thread_context_lookup(rb_thread_current());
1198
+ thread_context_lookup(rb_thread_current(), &current, NULL);
1183
1199
  for(i = 0; i < RARRAY(context_list)->len; i++)
1184
1200
  {
1185
1201
  context = rb_ary_entry(context_list, i);
@@ -1823,6 +1839,7 @@ Init_ruby_debug()
1823
1839
  rb_define_module_function(mDebugger, "last_context", debug_last_interrupted, 0);
1824
1840
  rb_define_module_function(mDebugger, "contexts", debug_contexts, 0);
1825
1841
  rb_define_module_function(mDebugger, "current_context", debug_current_context, 0);
1842
+ rb_define_module_function(mDebugger, "thread_context", debug_thread_context, 1);
1826
1843
  rb_define_module_function(mDebugger, "suspend", debug_suspend, 0);
1827
1844
  rb_define_module_function(mDebugger, "resume", debug_resume, 0);
1828
1845
  rb_define_module_function(mDebugger, "tracing", debug_tracing, 0);
@@ -1847,8 +1864,6 @@ Init_ruby_debug()
1847
1864
  idAtTracing = rb_intern("at_tracing");
1848
1865
  idEval = rb_intern("eval");
1849
1866
  idList = rb_intern("list");
1850
- idClear = rb_intern("clear");
1851
- idIndex = rb_intern("index");
1852
1867
 
1853
1868
  rb_mObjectSpace = rb_const_get(rb_mKernel, rb_intern("ObjectSpace"));
1854
1869
 
@@ -1856,4 +1871,6 @@ Init_ruby_debug()
1856
1871
  rb_global_variable(&breakpoints);
1857
1872
  rb_global_variable(&catchpoint);
1858
1873
  rb_global_variable(&locker);
1874
+ rb_global_variable(&last_context);
1875
+ rb_global_variable(&last_thread);
1859
1876
  }
data/lib/ruby-debug.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'pp'
2
2
  require 'stringio'
3
+ require "socket"
3
4
  require 'thread'
4
5
  require 'ruby_debug.so'
5
6
  require 'ruby-debug/processor'
@@ -56,11 +57,10 @@ module Debugger
56
57
  attr_reader :thread, :control_thread
57
58
 
58
59
  #
59
- # Interrupts the main thread
60
+ # Interrupts the current thread
60
61
  #
61
62
  def interrupt
62
- context = contexts.find{|c| c.thread == Thread.current }
63
- context.interrupt
63
+ current_context.interrupt
64
64
  end
65
65
 
66
66
  #
@@ -89,29 +89,18 @@ module Debugger
89
89
  start
90
90
  self.post_mortem if post_mortem
91
91
 
92
- require "socket"
93
-
94
92
  if port.kind_of?(Array)
95
93
  cmd_port, ctrl_port = port
96
94
  else
97
95
  cmd_port, ctrl_port = port, port + 1
98
96
  end
99
97
 
100
- @control_thread = Thread.start do
101
- current_context.ignore = true
102
- server = TCPServer.new(host, ctrl_port)
103
- while (session = server.accept)
104
- interface = RemoteInterface.new(session)
105
- processor = ControlCommandProcessor.new(interface)
106
- processor.process_commands
107
- end
108
- end
98
+ start_control(host, ctrl_port)
109
99
 
110
100
  mutex = Mutex.new
111
101
  proceed = ConditionVariable.new
112
102
 
113
- @thread = Thread.start do
114
- current_context.ignore = true
103
+ @thread = DebugThread.new do
115
104
  server = TCPServer.new(host, cmd_port)
116
105
  while (session = server.accept)
117
106
  self.interface = RemoteInterface.new(session)
@@ -133,6 +122,19 @@ module Debugger
133
122
  end
134
123
  alias start_server start_remote
135
124
 
125
+ def start_control(host = nil, ctrl_port = PORT + 1)
126
+ raise "Debugger is not started" unless started?
127
+ return if @control_thread
128
+ @control_thread = DebugThread.new do
129
+ server = TCPServer.new(host, ctrl_port)
130
+ while (session = server.accept)
131
+ interface = RemoteInterface.new(session)
132
+ processor = ControlCommandProcessor.new(interface)
133
+ processor.process_commands
134
+ end
135
+ end
136
+ end
137
+
136
138
  #
137
139
  # Connects to the remote debugger
138
140
  #
@@ -164,7 +166,7 @@ module Debugger
164
166
  def stop_main_thread # :nodoc:
165
167
  return unless stop_on_connect
166
168
 
167
- context = contexts.find{ |c| c.thread == Thread.main }
169
+ context = thread_context(Thread.main)
168
170
  context.stop_next = 2
169
171
  end
170
172
  private :stop_main_thread
@@ -272,6 +274,13 @@ class Exception # :nodoc:
272
274
  attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_frames
273
275
  end
274
276
 
277
+ class DebugThread < Thread # :nodoc:
278
+ def initialize(*args, &b)
279
+ Debugger.thread_context(self).ignore = true
280
+ super
281
+ end
282
+ end
283
+
275
284
  module Kernel
276
285
  #
277
286
  # Stops the current thread after a number of _steps_ made.
@@ -81,7 +81,7 @@ module Debugger
81
81
 
82
82
  def execute
83
83
  unless Debugger.interrupt_last
84
- context = Debugger.contexts.find{ |c| c.thread == Thread.main }
84
+ context = Debugger.thread_context(Thread.main)
85
85
  context.interrupt
86
86
  end
87
87
  end
@@ -1,5 +1,41 @@
1
1
  module Debugger
2
2
  module FrameFunctions # :nodoc:
3
+ def adjust_frame(frame_pos, absolute)
4
+ if absolute
5
+ if frame_pos < 0
6
+ abs_frame_pos = @state.frames.size + frame_pos
7
+ else
8
+ abs_frame_pos = frame_pos
9
+ end
10
+ else
11
+ abs_frame_pos = @state.frame_pos + frame_pos
12
+ end
13
+
14
+ if abs_frame_pos >= @state.frames.size then
15
+ print "Adjusting would put us beyond the oldest (initial) frame.\n"
16
+ return
17
+ elsif abs_frame_pos < 0 then
18
+ print "Adjusting would put us beyond the newest (innermost) frame.\n"
19
+ return
20
+ end
21
+ if @state.frame_pos != abs_frame_pos then
22
+ @state.previous_line = nil
23
+ @state.frame_pos = abs_frame_pos
24
+ end
25
+ frame = @state.frames[-1-@state.frame_pos]
26
+ @state.binding, @state.file, @state.line = frame.binding, frame.file, frame.line
27
+ print format_frame(frame, @state.frame_pos)
28
+ end
29
+
30
+ def get_int(str, cmd)
31
+ begin
32
+ return Integer(@match[1])
33
+ rescue
34
+ print "%s argument needs to be a number.\n" % cmd
35
+ return nil
36
+ end
37
+ end
38
+
3
39
  def format_frame(frame, pos)
4
40
  printf "\032\032" if ENV['EMACS']
5
41
  file, line, id = frame.file, frame.line, frame.id
@@ -11,7 +47,7 @@ module Debugger
11
47
  include FrameFunctions
12
48
 
13
49
  def regexp
14
- /^\s*(?:w(?:here)?|f(?:rame)?)$/
50
+ /^\s*(?:w(?:here)?|bt|backtrace)$/
15
51
  end
16
52
 
17
53
  def execute
@@ -37,7 +73,7 @@ module Debugger
37
73
  }
38
74
  else
39
75
  %{
40
- f[rame]\t\talias for where
76
+ bt|backtrace\t\talias for where
41
77
  }
42
78
  end
43
79
  end
@@ -48,46 +84,28 @@ module Debugger
48
84
  include FrameFunctions
49
85
 
50
86
  def regexp
51
- /^\s*(?:(up)(?:\s+(\d+))?|(f)(?:rame)?(?:\s+(\d+)))\s*$/
87
+ /^\s* u(?:p)? (?:\s+(.*))? .*$/x
52
88
  end
53
89
 
54
90
  def execute
55
- if @match[1]
56
- cmd, arg = @match.captures
57
- else
58
- cmd, arg = @match.captures[2..-1]
59
- end
60
- @state.previous_line = nil
61
- if cmd == 'f'
62
- @state.frame_pos = arg.to_i - 1
91
+ unless @match[1]
92
+ pos = 1
63
93
  else
64
- @state.frame_pos += (arg ? arg.to_i : 1)
94
+ pos = get_int(@match[1], "Up")
95
+ return unless pos
65
96
  end
66
- @state.frame_pos = 0 if @state.frame_pos < 0
67
- if @state.frame_pos >= @state.frames.size
68
- @state.frame_pos = @state.frames.size - 1
69
- print "At toplevel\n"
70
- end
71
- frame = @state.frames[-1 - @state.frame_pos]
72
- @state.binding, @state.file, @state.line = frame.binding, frame.file, frame.line
73
- print format_frame(frame, @state.frame_pos)
97
+ adjust_frame(pos, false)
74
98
  end
75
99
 
76
100
  class << self
77
101
  def help_command
78
- %w|up frame|
102
+ up
79
103
  end
80
104
 
81
105
  def help(cmd)
82
- if cmd == 'up'
83
- %{
84
- up[ nn]\tmove to higher frame
85
- }
86
- else
87
- %{
88
- f[rame] n\tselect nth frame
89
- }
90
- end
106
+ %{
107
+ up[count]\tmove to higher frame
108
+ }
91
109
  end
92
110
  end
93
111
  end
@@ -96,19 +114,17 @@ module Debugger
96
114
  include FrameFunctions
97
115
 
98
116
  def regexp
99
- /^\s*down(?:\s+(\d+))?$/
117
+ /^\s* d(?:own)? (?:\s+(.*))? .*$/x
100
118
  end
101
119
 
102
120
  def execute
103
- @state.previous_line = nil
104
- @state.frame_pos -= @match[1] ? @match[1].to_i : 1
105
- if @state.frame_pos < 0
106
- @state.frame_pos = 0
107
- print "At stack bottom\n"
121
+ if not @match[1]
122
+ pos = 1
123
+ else
124
+ pos = get_int(@match[1], "Down")
125
+ return unless pos
108
126
  end
109
- frame = @state.frames[-1 - @state.frame_pos]
110
- @state.binding, @state.file, @state.line = frame.binding, frame.file, frame.line
111
- print format_frame(frame, @state.frame_pos)
127
+ adjust_frame(-pos, false)
112
128
  end
113
129
 
114
130
  class << self
@@ -118,7 +134,42 @@ module Debugger
118
134
 
119
135
  def help(cmd)
120
136
  %{
121
- down[ nn]\tmove to lower frame
137
+ down[count]\tmove to lower frame
138
+ }
139
+ end
140
+ end
141
+ end
142
+
143
+ class FrameCommand < Command # :nodoc:
144
+ include FrameFunctions
145
+ def regexp
146
+ /^\s* f(?:rame)? (?:\s+ (.*))? \s*$/x
147
+ end
148
+
149
+ def execute
150
+ if not @match[1]
151
+ print "Missing a frame number argument.\n"
152
+ return
153
+ else
154
+ pos = get_int(@match[1], "Frame")
155
+ return unless pos
156
+ end
157
+ adjust_frame(pos < 0 ? pos : pos-1, true)
158
+ end
159
+
160
+ class << self
161
+ def help_command
162
+ 'frame'
163
+ end
164
+
165
+ def help(cmd)
166
+ %{
167
+ f[rame] frame-number
168
+ Move the current frame to the specified frame number.
169
+
170
+ A negative number indicates position from the other end. So
171
+ 'frame -1' moves to the oldest frame, and 'frame 0' moves to
172
+ the newest frame.
122
173
  }
123
174
  end
124
175
  end
data/lib/ruby_debug.so CHANGED
Binary file
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.1
3
3
  specification_version: 1
4
4
  name: ruby-debug
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.6.1
7
- date: 2007-01-26 21:24:26 -05:00
6
+ version: 0.6.2
7
+ date: 2007-01-28 14:26:27 -05:00
8
8
  summary: Fast Ruby debugger
9
9
  require_paths:
10
10
  - lib
@@ -33,9 +33,9 @@ files:
33
33
  - README
34
34
  - LICENSE
35
35
  - CHANGES
36
+ - AUTHORS
36
37
  - lib/ruby-debug
37
38
  - lib/ruby-debug.rb
38
- - lib/ruby_debug.so
39
39
  - lib/ruby-debug/command.rb
40
40
  - lib/ruby-debug/commands
41
41
  - lib/ruby-debug/interface.rb
@@ -61,6 +61,7 @@ files:
61
61
  - ext/tags
62
62
  - ext/win32
63
63
  - bin/rdebug
64
+ - lib/ruby_debug.so
64
65
  test_files: []
65
66
 
66
67
  rdoc_options: []