rb8-trepanning 0.1.3-universal-ruby-1.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (274) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGES +34 -0
  3. data/ChangeLog +875 -0
  4. data/README.textile +59 -0
  5. data/Rakefile +215 -0
  6. data/app/.gitignore +1 -0
  7. data/app/cmd_parse.kpeg +241 -0
  8. data/app/cmd_parse.rb +212 -0
  9. data/app/cmd_parser.rb +1948 -0
  10. data/app/complete.rb +79 -0
  11. data/app/default.rb +90 -0
  12. data/app/display.rb +148 -0
  13. data/app/eventbuffer.rb +147 -0
  14. data/app/frame.rb +166 -0
  15. data/app/irb.rb +114 -0
  16. data/app/options.rb +200 -0
  17. data/app/run.rb +74 -0
  18. data/app/util.rb +65 -0
  19. data/bin/.gitignore +1 -0
  20. data/bin/trepan8 +115 -0
  21. data/data/.gitignore +1 -0
  22. data/data/irbrc +41 -0
  23. data/interface/.gitignore +1 -0
  24. data/interface/base_intf.rb +109 -0
  25. data/interface/client.rb +82 -0
  26. data/interface/comcodes.rb +20 -0
  27. data/interface/script.rb +110 -0
  28. data/interface/server.rb +147 -0
  29. data/interface/user.rb +165 -0
  30. data/io/base_io.rb +148 -0
  31. data/io/input.rb +158 -0
  32. data/io/null_output.rb +46 -0
  33. data/io/string_array.rb +156 -0
  34. data/io/tcpclient.rb +129 -0
  35. data/io/tcpfns.rb +33 -0
  36. data/io/tcpserver.rb +141 -0
  37. data/lib/debugger.rb +8 -0
  38. data/lib/trepanning.rb +283 -0
  39. data/processor/.gitignore +1 -0
  40. data/processor/command-ruby-debug/breakpoints.rb +155 -0
  41. data/processor/command-ruby-debug/catchpoint.rb +55 -0
  42. data/processor/command-ruby-debug/condition.rb +49 -0
  43. data/processor/command-ruby-debug/control.rb +31 -0
  44. data/processor/command-ruby-debug/display.rb +120 -0
  45. data/processor/command-ruby-debug/enable.rb +202 -0
  46. data/processor/command-ruby-debug/frame.rb +199 -0
  47. data/processor/command-ruby-debug/help.rb +63 -0
  48. data/processor/command-ruby-debug/info.rb +359 -0
  49. data/processor/command-ruby-debug/method.rb +84 -0
  50. data/processor/command-ruby-debug/reload.rb +40 -0
  51. data/processor/command-ruby-debug/save.rb +90 -0
  52. data/processor/command-ruby-debug/set.rb +237 -0
  53. data/processor/command-ruby-debug/show.rb +251 -0
  54. data/processor/command-ruby-debug/source.rb +36 -0
  55. data/processor/command-ruby-debug/threads.rb +189 -0
  56. data/processor/command-ruby-debug/trace.rb +57 -0
  57. data/processor/command-ruby-debug/variables.rb +199 -0
  58. data/processor/command.rb +270 -0
  59. data/processor/command/.gitignore +1 -0
  60. data/processor/command/alias.rb +54 -0
  61. data/processor/command/backtrace.rb +123 -0
  62. data/processor/command/base/cmd.rb +177 -0
  63. data/processor/command/base/subcmd.rb +230 -0
  64. data/processor/command/base/submgr.rb +188 -0
  65. data/processor/command/base/subsubcmd.rb +128 -0
  66. data/processor/command/base/subsubmgr.rb +199 -0
  67. data/processor/command/break.rb +114 -0
  68. data/processor/command/catch.rb +71 -0
  69. data/processor/command/complete.rb +39 -0
  70. data/processor/command/continue.rb +57 -0
  71. data/processor/command/directory.rb +50 -0
  72. data/processor/command/disable.rb +85 -0
  73. data/processor/command/display.rb +78 -0
  74. data/processor/command/down.rb +54 -0
  75. data/processor/command/edit.rb +79 -0
  76. data/processor/command/enable.rb +48 -0
  77. data/processor/command/eval.rb +90 -0
  78. data/processor/command/exit.rb +66 -0
  79. data/processor/command/finish.rb +59 -0
  80. data/processor/command/frame.rb +97 -0
  81. data/processor/command/help.rb +230 -0
  82. data/processor/command/help/.gitignore +1 -0
  83. data/processor/command/help/README +10 -0
  84. data/processor/command/help/command.txt +58 -0
  85. data/processor/command/help/examples.txt +16 -0
  86. data/processor/command/help/filename.txt +40 -0
  87. data/processor/command/help/location.txt +37 -0
  88. data/processor/command/help/suffixes.txt +17 -0
  89. data/processor/command/info.rb +28 -0
  90. data/processor/command/info_subcmd/.gitignore +1 -0
  91. data/processor/command/info_subcmd/args.rb +39 -0
  92. data/processor/command/info_subcmd/breakpoints.rb +80 -0
  93. data/processor/command/info_subcmd/catch.rb +36 -0
  94. data/processor/command/info_subcmd/files.rb +39 -0
  95. data/processor/command/info_subcmd/globals.rb +64 -0
  96. data/processor/command/info_subcmd/line.rb +30 -0
  97. data/processor/command/info_subcmd/locals.rb +69 -0
  98. data/processor/command/info_subcmd/macro.rb +62 -0
  99. data/processor/command/info_subcmd/program.rb +51 -0
  100. data/processor/command/info_subcmd/ruby.rb +57 -0
  101. data/processor/command/info_subcmd/source.rb +74 -0
  102. data/processor/command/info_subcmd/stack.rb +25 -0
  103. data/processor/command/info_subcmd/threads.rb +75 -0
  104. data/processor/command/kill.rb +78 -0
  105. data/processor/command/list.rb +117 -0
  106. data/processor/command/macro.rb +68 -0
  107. data/processor/command/next.rb +79 -0
  108. data/processor/command/parsetree.rb +56 -0
  109. data/processor/command/pp.rb +40 -0
  110. data/processor/command/pr.rb +37 -0
  111. data/processor/command/ps.rb +40 -0
  112. data/processor/command/restart.rb +86 -0
  113. data/processor/command/save.rb +58 -0
  114. data/processor/command/set.rb +47 -0
  115. data/processor/command/set_subcmd/.gitignore +1 -0
  116. data/processor/command/set_subcmd/abbrev.rb +25 -0
  117. data/processor/command/set_subcmd/auto.rb +27 -0
  118. data/processor/command/set_subcmd/auto_subcmd/.gitignore +1 -0
  119. data/processor/command/set_subcmd/auto_subcmd/eval.rb +53 -0
  120. data/processor/command/set_subcmd/auto_subcmd/irb.rb +33 -0
  121. data/processor/command/set_subcmd/auto_subcmd/list.rb +33 -0
  122. data/processor/command/set_subcmd/basename.rb +25 -0
  123. data/processor/command/set_subcmd/callstyle.rb +46 -0
  124. data/processor/command/set_subcmd/confirm.rb +24 -0
  125. data/processor/command/set_subcmd/debug.rb +47 -0
  126. data/processor/command/set_subcmd/different.rb +61 -0
  127. data/processor/command/set_subcmd/highlight.rb +43 -0
  128. data/processor/command/set_subcmd/max.rb +26 -0
  129. data/processor/command/set_subcmd/max_subcmd/list.rb +49 -0
  130. data/processor/command/set_subcmd/max_subcmd/stack.rb +50 -0
  131. data/processor/command/set_subcmd/max_subcmd/string.rb +76 -0
  132. data/processor/command/set_subcmd/max_subcmd/width.rb +49 -0
  133. data/processor/command/set_subcmd/reload.rb +42 -0
  134. data/processor/command/set_subcmd/timer.rb +58 -0
  135. data/processor/command/set_subcmd/trace.rb +37 -0
  136. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +42 -0
  137. data/processor/command/set_subcmd/trace_subcmd/print.rb +41 -0
  138. data/processor/command/shell.rb +139 -0
  139. data/processor/command/show.rb +39 -0
  140. data/processor/command/show_subcmd/.gitignore +1 -0
  141. data/processor/command/show_subcmd/abbrev.rb +20 -0
  142. data/processor/command/show_subcmd/alias.rb +46 -0
  143. data/processor/command/show_subcmd/args.rb +34 -0
  144. data/processor/command/show_subcmd/auto.rb +28 -0
  145. data/processor/command/show_subcmd/auto_subcmd/eval.rb +27 -0
  146. data/processor/command/show_subcmd/auto_subcmd/irb.rb +23 -0
  147. data/processor/command/show_subcmd/auto_subcmd/list.rb +22 -0
  148. data/processor/command/show_subcmd/basename.rb +20 -0
  149. data/processor/command/show_subcmd/callstyle.rb +22 -0
  150. data/processor/command/show_subcmd/confirm.rb +18 -0
  151. data/processor/command/show_subcmd/debug.rb +26 -0
  152. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +21 -0
  153. data/processor/command/show_subcmd/debug_subcmd/skip.rb +22 -0
  154. data/processor/command/show_subcmd/debug_subcmd/step.rb +22 -0
  155. data/processor/command/show_subcmd/different.rb +26 -0
  156. data/processor/command/show_subcmd/directories.rb +22 -0
  157. data/processor/command/show_subcmd/highlight.rb +24 -0
  158. data/processor/command/show_subcmd/max.rb +27 -0
  159. data/processor/command/show_subcmd/max_subcmd/list.rb +38 -0
  160. data/processor/command/show_subcmd/max_subcmd/stack.rb +36 -0
  161. data/processor/command/show_subcmd/max_subcmd/string.rb +42 -0
  162. data/processor/command/show_subcmd/max_subcmd/width.rb +37 -0
  163. data/processor/command/show_subcmd/reload.rb +18 -0
  164. data/processor/command/show_subcmd/timer.rb +18 -0
  165. data/processor/command/show_subcmd/trace.rb +29 -0
  166. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +65 -0
  167. data/processor/command/show_subcmd/trace_subcmd/print.rb +23 -0
  168. data/processor/command/show_subcmd/version.rb +23 -0
  169. data/processor/command/source.rb +134 -0
  170. data/processor/command/step.rb +81 -0
  171. data/processor/command/tbreak.rb +19 -0
  172. data/processor/command/unalias.rb +44 -0
  173. data/processor/command/undisplay.rb +59 -0
  174. data/processor/command/up.rb +72 -0
  175. data/processor/default.rb +56 -0
  176. data/processor/display.rb +17 -0
  177. data/processor/eval.rb +113 -0
  178. data/processor/eventbuf.rb +105 -0
  179. data/processor/frame.rb +172 -0
  180. data/processor/help.rb +92 -0
  181. data/processor/helper.rb +76 -0
  182. data/processor/hook.rb +134 -0
  183. data/processor/load_cmds.rb +258 -0
  184. data/processor/location.rb +174 -0
  185. data/processor/main.rb +455 -0
  186. data/processor/mock.rb +136 -0
  187. data/processor/msg.rb +61 -0
  188. data/processor/processor.rb +674 -0
  189. data/processor/running.rb +168 -0
  190. data/processor/stepping.rb +18 -0
  191. data/processor/subcmd.rb +161 -0
  192. data/processor/validate.rb +355 -0
  193. data/processor/virtual.rb +34 -0
  194. data/test/data/.gitignore +1 -0
  195. data/test/data/break_bad.cmd +19 -0
  196. data/test/data/break_bad.right +29 -0
  197. data/test/data/break_loop_bug.cmd +5 -0
  198. data/test/data/break_loop_bug.right +15 -0
  199. data/test/data/dollar-0.right +2 -0
  200. data/test/data/dollar-0a.right +2 -0
  201. data/test/data/dollar-0b.right +2 -0
  202. data/test/data/edit.cmd +14 -0
  203. data/test/data/edit.right +24 -0
  204. data/test/data/file-with-space.cmd +6 -0
  205. data/test/data/file-with-space.right +4 -0
  206. data/test/data/printvar.cmd +17 -0
  207. data/test/data/printvar.right +31 -0
  208. data/test/data/raise.cmd +11 -0
  209. data/test/data/raise.right +19 -0
  210. data/test/data/source.cmd +5 -0
  211. data/test/data/source.right +18 -0
  212. data/test/data/stepping-1.9.right +50 -0
  213. data/test/data/stepping.cmd +21 -0
  214. data/test/data/stepping.right +48 -0
  215. data/test/data/trepan8-save.1 +6 -0
  216. data/test/example/bp_loop_issue.rb +3 -0
  217. data/test/example/break-bug.rb +7 -0
  218. data/test/example/brkpt-class-bug.rb +8 -0
  219. data/test/example/classes.rb +11 -0
  220. data/test/example/dollar-0.rb +5 -0
  221. data/test/example/except-bug1.rb +4 -0
  222. data/test/example/except-bug2.rb +7 -0
  223. data/test/example/file with space.rb +1 -0
  224. data/test/example/gcd.rb +18 -0
  225. data/test/example/info-var-bug.rb +47 -0
  226. data/test/example/info-var-bug2.rb +2 -0
  227. data/test/example/null.rb +1 -0
  228. data/test/example/pm-bug.rb +3 -0
  229. data/test/example/pm.rb +11 -0
  230. data/test/example/raise.rb +3 -0
  231. data/test/integration/.gitignore +4 -0
  232. data/test/integration/config.yaml +8 -0
  233. data/test/integration/helper.rb +154 -0
  234. data/test/integration/test-break_bad.rb +26 -0
  235. data/test/integration/test-dollar-0.rb +31 -0
  236. data/test/integration/test-edit.rb +17 -0
  237. data/test/integration/test-file-with-space.rb +26 -0
  238. data/test/integration/test-printvar.rb +17 -0
  239. data/test/integration/test-raise.rb +21 -0
  240. data/test/integration/test-source.rb +16 -0
  241. data/test/integration/test-stepping.rb +24 -0
  242. data/test/unit/.gitignore +1 -0
  243. data/test/unit/cmd-helper.rb +52 -0
  244. data/test/unit/mock-helper.rb +12 -0
  245. data/test/unit/test-app-cmd_parse.rb +97 -0
  246. data/test/unit/test-app-cmd_parser.rb +23 -0
  247. data/test/unit/test-app-complete.rb +39 -0
  248. data/test/unit/test-app-frame.rb +32 -0
  249. data/test/unit/test-app-options.rb +92 -0
  250. data/test/unit/test-app-run.rb +14 -0
  251. data/test/unit/test-app-util.rb +44 -0
  252. data/test/unit/test-base-cmd.rb +45 -0
  253. data/test/unit/test-base-subcmd.rb +57 -0
  254. data/test/unit/test-base-submgr.rb +23 -0
  255. data/test/unit/test-base-subsubcmd.rb +17 -0
  256. data/test/unit/test-cmd-alias.rb +48 -0
  257. data/test/unit/test-cmd-exit.rb +27 -0
  258. data/test/unit/test-cmd-help.rb +104 -0
  259. data/test/unit/test-cmd-kill.rb +46 -0
  260. data/test/unit/test-cmd-source.rb +34 -0
  261. data/test/unit/test-completion.rb +42 -0
  262. data/test/unit/test-intf-user.rb +46 -0
  263. data/test/unit/test-io-input.rb +27 -0
  264. data/test/unit/test-io-tcp.rb +33 -0
  265. data/test/unit/test-io-tcpclient.rb +54 -0
  266. data/test/unit/test-io-tcpfns.rb +17 -0
  267. data/test/unit/test-io-tcpserver.rb +50 -0
  268. data/test/unit/test-proc-eval.rb +36 -0
  269. data/test/unit/test-proc-hook.rb +30 -0
  270. data/test/unit/test-proc-load_cmds.rb +50 -0
  271. data/test/unit/test-proc-location.rb +79 -0
  272. data/test/unit/test-subcmd-help.rb +44 -0
  273. data/trepan8.gemspec +58 -0
  274. metadata +388 -0
@@ -0,0 +1,168 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'rubygems'
3
+ require 'require_relative'
4
+ require_relative 'virtual'
5
+ class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
6
+
7
+ attr_accessor :stop_condition # String or nil. When not nil
8
+ # this has to eval non-nil
9
+ # in order to stop.
10
+ attr_accessor :stop_events # Set or nil. If not nil, only
11
+ # events in this set will be
12
+ # considered for stopping. This is
13
+ # like core.step_events (which
14
+ # could be used instead), but it is
15
+ # a set of event names rather than
16
+ # a bitmask and it is intended to
17
+ # be more temporarily changed via
18
+ # "step>" or "step!" commands.
19
+ attr_accessor :to_method
20
+
21
+ # Does whatever needs to be done to set to continue program
22
+ # execution.
23
+ def continue
24
+ @state.proceed
25
+ end
26
+
27
+ # # Does whatever setup needs to be done to set to ignore stepping
28
+ # # to the finish of the current method.
29
+ # def finish(level_count=0, opts={})
30
+ # step(0, opts)
31
+ # @next_level = @frame.stack_size - level_count
32
+ # @next_thread = Thread.current
33
+ # @stop_events = Set.new(%w(return leave yield))
34
+
35
+ # # Try high-speed (run-time-assisted) method
36
+ # @frame.trace_off = true # No more tracing in this frame
37
+ # @frame.return_stop = true # don't need to
38
+ # end
39
+
40
+ # # Does whatever needs to be done to set to do "step over" or ignore
41
+ # # stepping into methods called from this stack but step into any in
42
+ # # the same level. We do this by keeping track of the number of
43
+ # # stack frames and the current thread. Elsewhere in "skipping_step?"
44
+ # # we do the checking.
45
+ # def next(step_count=1, opts={})
46
+ # step(step_count, opts)
47
+ # @next_level = @top_frame.stack_size
48
+ # @next_thread = Thread.current
49
+ # end
50
+
51
+ # # Does whatever needs to be done to set to step program
52
+ # # execution.
53
+ # def step(step_count=1, opts={}, condition=nil)
54
+ # continue
55
+ # @core.step_count = step_count
56
+ # @different_pos = opts[:different_pos] if
57
+ # opts.keys.member?(:different_pos)
58
+ # @stop_condition = condition
59
+ # @stop_events = opts[:stop_events] if
60
+ # opts.keys.member?(:stop_events)
61
+ # @to_method = opts[:to_method]
62
+ # end
63
+
64
+ def quit(cmd='quit')
65
+ @next_level = 32000 # I'm guessing the stack size can't
66
+ # ever reach this
67
+ @next_thread = nil
68
+ @context.stop_next = 0 # No more event stepping
69
+ @leave_cmd_loop = true # Break out of the processor command loop.
70
+ @settings[:autoirb] = false
71
+ ## @cmdloop_prehooks.delete_by_name('autoirb')
72
+ @commands['exit'].run([cmd])
73
+ end
74
+
75
+ def parse_next_step_suffix(step_cmd)
76
+ opts = {}
77
+ case step_cmd[-1..-1]
78
+ when '-'
79
+ opts[:different_pos] = false
80
+ when '+'
81
+ opts[:different_pos] = 'nostack'
82
+ when '='
83
+ opts[:different_pos] = true
84
+ when '!'
85
+ opts[:stop_events] = Set.new(%w(raise))
86
+ when '<'
87
+ opts[:stop_events] = Set.new(%w(c-return return))
88
+ when '>'
89
+ opts[:stop_events] = Set.new(%w(c-call call))
90
+ if step_cmd.size > 1 && step_cmd[-2..-2] == '<'
91
+ opts[:stop_events] = Set.new(%w(c-call c-return call return))
92
+ else
93
+ opts[:stop_events] = Set.new(%w(c-call call))
94
+ end
95
+ end
96
+ return opts
97
+ end
98
+
99
+ def running_initialize
100
+ @stop_condition = nil
101
+ @stop_events = nil
102
+ @to_method = nil
103
+ end
104
+
105
+ # def stepping_skip?
106
+
107
+ # return true if @core.step_count < 0
108
+
109
+ # if @settings[:'debugskip']
110
+ # msg "diff: #{@different_pos}, event : #{@event}, #{@stop_events.inspect}"
111
+ # msg "step_count : #{@core.step_count}"
112
+ # msg "next_level : #{@next_level}, ssize : #{@stack_size}"
113
+ # msg "next_thread : #{@next_thread}, thread: #{Thread.current}"
114
+ # end
115
+
116
+ # return true if
117
+ # !frame || (@next_level < @frame.stack_size &&
118
+ # Thread.current == @next_thread)
119
+
120
+ # new_pos = [@frame.source_container, frame_line,
121
+ # @stack_size, @current_thread, @event, @frame.pc_offset]
122
+
123
+ # skip_val = @stop_events && !@stop_events.member?(@event)
124
+
125
+ # # If the last stop was a breakpoint, don't stop again if we are at
126
+ # # the same location with a line event.
127
+ # skip_val ||= (@last_pos[4] == 'brkpt' &&
128
+ # @event == 'line' &&
129
+ # @frame.pc_offset == @last_pos[5])
130
+
131
+ # if @settings[:'debugskip']
132
+ # puts "skip: #{skip_val.inspect}, last: #{@last_pos}, new: #{new_pos}"
133
+ # end
134
+
135
+ # @last_pos[2] = new_pos[2] if 'nostack' == @different_pos
136
+ # unless skip_val
137
+ # condition_met =
138
+ # if @stop_condition
139
+ # puts 'stop_cond' if @settings[:'debugskip']
140
+ # debug_eval_no_errmsg(@stop_condition)
141
+ # elsif @to_method
142
+ # puts "method #{@frame.method} #{@to_method}" if
143
+ # @settings[:'debugskip']
144
+ # @frame.method == @to_method
145
+ # else
146
+ # puts 'uncond' if @settings[:'debugskip']
147
+ # true
148
+ # end
149
+
150
+ # msg("condition_met: #{condition_met}, last: #{@last_pos}, " +
151
+ # "new: #{new_pos}, different #{@different_pos.inspect}") if
152
+ # @settings[:'debugskip']
153
+ # skip_val = ((@last_pos[0..3] == new_pos[0..3] && @different_pos) ||
154
+ # !condition_met)
155
+ # end
156
+
157
+ # @last_pos = new_pos if !@stop_events || @stop_events.member?(@event)
158
+
159
+ # unless skip_val
160
+ # # Set up the default values for the
161
+ # # next time we consider skipping.
162
+ # @different_pos = @settings[:different]
163
+ # @stop_events = nil
164
+ # end
165
+
166
+ # return skip_val
167
+ # end
168
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright (C) 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'rubygems'; require 'require_relative'
3
+ require_relative 'virtual'
4
+ module Trepan
5
+ class CmdProcessor < VirtualCmdProcessor
6
+ def parse_stepping_args(command_name, match)
7
+ if match[1].nil?
8
+ different = @settings[:force_stepping]
9
+ elsif match[1] == '+'
10
+ different = true
11
+ elsif match[1] == '-'
12
+ different = false
13
+ end
14
+ steps = get_int(match[2], command_name, 1)
15
+ return [steps, different]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,161 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # gdb-like subcommand processing.
3
+
4
+ module Trepan
5
+ class Subcmd
6
+
7
+ attr_reader :subcmds # Hash of subcommands. Key is the subcommand name.
8
+ # the value is the subcommand object to run.
9
+ def initialize(cmd)
10
+ @cmd = cmd
11
+ @subcmds = {}
12
+ @cmdlist = []
13
+ end
14
+
15
+ # Find subcmd in self.subcmds
16
+ def lookup(subcmd_prefix, use_regexp=true)
17
+ compare = if use_regexp
18
+ lambda{|name| name.to_s =~ /^#{subcmd_prefix}/}
19
+ else
20
+ lambda{|name| 0 == name.to_s.index(subcmd_prefix)}
21
+ end
22
+ @subcmds.each do |subcmd_name, subcmd|
23
+ if compare.call(subcmd_name) &&
24
+ subcmd_prefix.size >= subcmd.class.const_get(:MIN_ABBREV)
25
+ return subcmd
26
+ end
27
+ end
28
+ return nil
29
+ end
30
+
31
+ # Show short help for a subcommand.
32
+ def short_help(subcmd_cb, subcmd_name, label=false)
33
+ entry = self.lookup(subcmd_name)
34
+ if entry
35
+ if label
36
+ prefix = entry.name
37
+ else
38
+ prefix = ''
39
+ end
40
+ if entry.respond_to?(:short_help)
41
+ prefix += ' -- ' if prefix
42
+ @proc.msg(prefix + entry.short_help)
43
+ end
44
+ else
45
+ @proc.undefined_subcmd("help", subcmd_name)
46
+ end
47
+ end
48
+
49
+ # Add subcmd to the available subcommands for this object.
50
+ # It will have the supplied docstring, and subcmd_cb will be called
51
+ # when we want to run the command. min_len is the minimum length
52
+ # allowed to abbreviate the command. in_list indicates with the
53
+ # show command will be run when giving a list of all sub commands
54
+ # of this object. Some commands have long output like "show commands"
55
+ # so we might not want to show that.
56
+ def add(subcmd_cb, subcmd_name=nil)
57
+ subcmd_name ||= subcmd_cb.name
58
+ @subcmds[subcmd_name.to_s] = subcmd_cb
59
+
60
+ # We keep a list of subcommands to assist command completion
61
+ @cmdlist << subcmd_name
62
+ end
63
+
64
+ # Run subcmd_name with args using obj for the environent
65
+ def run( subcmd_name, arg)
66
+ entry=lookup(subcmd_name)
67
+ if entry
68
+ entry['callback'].send(arg)
69
+ else
70
+ @proc.undefined_cmd(entry.__class__.name, subcmd_name)
71
+ end
72
+ end
73
+
74
+ # help for subcommands
75
+ # Note: format of help is compatible with ddd.
76
+ def help(*args)
77
+
78
+ msg args
79
+ subcmd_prefix = args[0]
80
+ if not subcmd_prefix or subcmd_prefix.size == 0
81
+ @proc.msg(self.doc)
82
+ @proc.msg("\nList of %s subcommands:\n" % [@name])
83
+ @list.each do |subcmd_name|
84
+ subcmd_helper(subcmd_name, obj, true, true)
85
+ end
86
+
87
+ entry = lookup(subcmd_prefix)
88
+ if entry and entry.respond_to? :help
89
+ entry.help(args)
90
+ else
91
+ @proc.errmsg("Unknown 'help %s' subcommand %s" %
92
+ [@name, subcmd_prefix])
93
+ end
94
+ end
95
+ end
96
+
97
+ def list
98
+ @subcmds.keys.sort
99
+ end
100
+
101
+ # Error message when a subcommand doesn't exist.
102
+ def undefined_subcmd(cmd, subcmd)
103
+ @proc.errmsg('Undefined "%s" command: "%s". Try "help".' %
104
+ [cmd, subcmd])
105
+ end
106
+ end
107
+ end
108
+
109
+ # When invoked as main program, invoke the debugger on a script
110
+ if __FILE__ == $0
111
+
112
+ require 'rubygems'; require 'require_relative'
113
+ require_relative 'mock'
114
+ require_relative 'command/base/cmd'
115
+
116
+ class Trepan::TestCommand < Trepan::Command
117
+
118
+ HELP = 'Help string string for testing'
119
+ CATEGORY = 'data'
120
+ MIN_ARGS = 0
121
+ MAX_ARGS = 5
122
+ NAME_ALIASES = %w(test)
123
+
124
+ def initialize(proc); @proc = proc end
125
+
126
+ def run(args); puts 'test command run' end
127
+ end
128
+
129
+ class TestTestingSubcommand
130
+ HELP = 'Help string for test testing subcommand'
131
+
132
+ def initialize; @name = 'testing' end
133
+
134
+ SHORT_HELP = 'This is short help for test testing'
135
+ MIN_ABREV = 4
136
+ IN_LIST = true
137
+ def run(args); puts 'test testing run' end
138
+ end
139
+
140
+ d = MockDebugger::MockDebugger.new
141
+ testcmd = Trepan::TestCommand.new(nil)
142
+ # testcmd.debugger = d
143
+ # testcmd.proc = d.core.processor
144
+ # testcmdMgr = Subcmd.new('test', testcmd)
145
+ # testsub = TestTestingSubcommand.new
146
+ # testcmdMgr.add(testsub)
147
+
148
+ # %w(tes test testing testing1).each do |prefix|
149
+ # x = testcmdMgr.lookup(prefix)
150
+ # puts x ? x.name : 'Non'
151
+ # end
152
+
153
+ # testcmdMgr.short_help(testcmd, 'testing')
154
+ # testcmdMgr.short_help(testcmd, 'test', true)
155
+ # testcmdMgr.short_help(testcmd, 'tes')
156
+ # puts testcmdMgr.list()
157
+ # testsub2 = TestTestingSubcommand.new
158
+ # testsub2.name = 'foobar'
159
+ # testcmdMgr.add(testsub2)
160
+ # puts testcmdMgr.list()
161
+ end
@@ -0,0 +1,355 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+
3
+ # Trepan command input validation routines. A String type is
4
+ # usually passed in as the argument to validation routines.
5
+
6
+ require 'rubygems'
7
+ require 'require_relative'
8
+ begin
9
+ require 'linecache'
10
+ rescue LoadError
11
+ require 'linecache19'
12
+ end
13
+
14
+ require_relative '../app/cmd_parse'
15
+ # require_relative '../app/condition'
16
+ # require_relative '../app/file'
17
+ # require_relative '../app/method'
18
+ # require_relative '../app/validate'
19
+
20
+ ## require_relative 'location' # for resolve_file_with_dir
21
+ require_relative 'virtual'
22
+ require_relative 'msg' # for errmsg, msg
23
+
24
+ class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
25
+
26
+ attr_reader :file_exists_proc # Like File.exists? but checks using
27
+ # cached files
28
+
29
+ ## include Trepanning::Method
30
+ ## include Trepanning::FileName
31
+ ## include Trepan::Validate
32
+ ## include Trepan::ThreadHelper
33
+ ## include Trepan::Condition
34
+
35
+ def confirm(msg, default)
36
+ @settings[:confirm] ? @intf.confirm(msg, default) : true
37
+ end
38
+
39
+ # Like cmdfns.get_an_int(), but if there's a stack frame use that
40
+ # in evaluation.
41
+ def get_an_int(arg, opts={})
42
+ ret_value = get_int_noerr(arg)
43
+ if !ret_value
44
+ if opts[:msg_on_error]
45
+ errmsg(opts[:msg_on_error])
46
+ else
47
+ errmsg("Expecting an integer, got: #{arg}.")
48
+ end
49
+ return nil
50
+ end
51
+ if opts[:min_value] and ret_value < opts[:min_value]
52
+ errmsg("Expecting integer value to be at least %d; got %d." %
53
+ [opts[:min_value], ret_value])
54
+ return nil
55
+ elsif opts[:max_value] and ret_value > opts[:max_value]
56
+ errmsg("Expecting integer value to be at most %d; got %d." %
57
+ [opts[:max_value], ret_value])
58
+ return nil
59
+ end
60
+ return ret_value
61
+ end
62
+
63
+ unless defined?(DEFAULT_GET_INT_OPTS)
64
+ DEFAULT_GET_INT_OPTS = {
65
+ :min_value => 0, :default => 1, :cmdname => nil, :max_value => nil}
66
+ end
67
+
68
+ # If argument parameter 'arg' is not given, then use what is in
69
+ # opts[:default]. If String 'arg' evaluates to an integer between
70
+ # least min_value and at_most, use that. Otherwise report an
71
+ # error. If there's a stack frame use that for bindings in
72
+ # evaluation.
73
+ def get_int(arg, opts={})
74
+
75
+ return default unless arg
76
+ opts = DEFAULT_GET_INT_OPTS.merge(opts)
77
+ val = arg ? get_int_noerr(arg) : opts[:default]
78
+ unless val
79
+ if opts[:cmdname]
80
+ errmsg(("Command '%s' expects an integer; " +
81
+ "got: %s.") % [opts[:cmdname], arg])
82
+ else
83
+ errmsg('Expecting a positive integer, got: %s' % arg)
84
+ end
85
+ return nil
86
+ end
87
+
88
+ if val < opts[:min_value]
89
+ if opts[:cmdname]
90
+ errmsg(("Command '%s' expects an integer at least" +
91
+ ' %d; got: %d.') %
92
+ [opts[:cmdname], opts[:min_value], opts[:default]])
93
+ else
94
+ errmsg(("Expecting a positive integer at least" +
95
+ ' %d; got: %d') %
96
+ [opts[:min_value], opts[:default]])
97
+ end
98
+ return nil
99
+ elsif opts[:max_value] and val > opts[:max_value]
100
+ if opts[:cmdname]
101
+ errmsg(("Command '%s' expects an integer at most" +
102
+ ' %d; got: %d.') %
103
+ [opts[:cmdname], opts[:max_value], val])
104
+ else
105
+ errmsg(("Expecting an integer at most %d; got: %d") %
106
+ [opts[:max_value], val])
107
+ end
108
+ return nil
109
+ end
110
+ return val
111
+ end
112
+
113
+ def get_int_list(args, opts={})
114
+ args.map{|arg| get_an_int(arg, opts)}.compact
115
+ end
116
+
117
+ # Eval arg and it is an integer return the value. Otherwise
118
+ # return nil
119
+ def get_int_noerr(arg)
120
+ b = @frame ? @frame.binding : nil
121
+ val = Integer(eval(arg, b))
122
+ rescue SyntaxError
123
+ nil
124
+ rescue
125
+ nil
126
+ end
127
+
128
+ def get_thread_from_string(id_or_num_str)
129
+ if id_or_num_str == '.'
130
+ Thread.current
131
+ elsif id_or_num_str.downcase == 'm'
132
+ Thread.main
133
+ else
134
+ num = get_int_noerr(id_or_num_str)
135
+ if num
136
+ get_thread(num)
137
+ else
138
+ nil
139
+ end
140
+ end
141
+ end
142
+
143
+ # Parse a breakpoint position. On success return:
144
+ # - the Method the position is in
145
+ # - the file name - a Fixnum
146
+ # - the line number - a Fixnum
147
+ # - the condition (by default 'true') to use for this breakpoint
148
+ # - true condition should be negated. Used in *condition* if/unless
149
+ def breakpoint_position(position_str, allow_condition)
150
+ break_cmd_parse = if allow_condition
151
+ parse_breakpoint(position_str)
152
+ else
153
+ parse_breakpoint_no_condition(position_str)
154
+ end
155
+ return [nil] * 5 unless break_cmd_parse
156
+ tail = [break_cmd_parse.condition, break_cmd_parse.negate]
157
+ cm, file, line, position_type =
158
+ parse_position(break_cmd_parse.position)
159
+ if cm or file or line
160
+ return [cm, file, line, position_type] + tail
161
+ end
162
+ errmsg("Unable to get breakpoint position for #{position_str}")
163
+ return [nil] * 5
164
+ end
165
+
166
+ # Return true if arg is 'on' or 1 and false arg is 'off' or 0.
167
+ # Any other value is raises TypeError.
168
+ def get_onoff(arg, default=nil, print_error=true)
169
+ unless arg
170
+ if !default
171
+ if print_error
172
+ errmsg("Expecting 'on', 1, 'off', or 0. Got nothing.")
173
+ end
174
+ raise TypeError
175
+ end
176
+ return default
177
+ end
178
+ darg = arg.downcase
179
+ return true if arg == '1' || darg == 'on'
180
+ return false if arg == '0' || darg =='off'
181
+
182
+ errmsg("Expecting 'on', 1, 'off', or 0. Got: %s." % arg.to_s) if
183
+ print_error
184
+ raise TypeError
185
+ end
186
+
187
+ include Trepan::CmdParser
188
+
189
+ def get_method(meth)
190
+ start_binding =
191
+ begin
192
+ @frame.binding
193
+ rescue
194
+ binding
195
+ end
196
+ if meth.kind_of?(String)
197
+ meth_for_string(meth, start_binding)
198
+ else
199
+ begin
200
+ meth_for_parse_struct(meth, start_binding)
201
+ rescue NameError
202
+ errmsg("Can't evaluate #{meth.name} to get a method")
203
+ return nil
204
+ end
205
+ end
206
+ end
207
+
208
+ # FIXME: this is a ? method but we return
209
+ # the method value.
210
+ def method?(meth)
211
+ get_method(meth)
212
+ end
213
+
214
+ # parse_position(self)->(meth, filename, offset, offset_type)
215
+ # See app/cmd_parser.kpeg for the syntax of a position which
216
+ # should include things like:
217
+ # Parse arg as [filename:]lineno | function | module
218
+ # Make sure it works for C:\foo\bar.py:12
219
+ def parse_position(info)
220
+ info = parse_location(info) if info.kind_of?(String)
221
+ case info.container_type
222
+ when :fn
223
+ unless info.container
224
+ errmsg "Bad function parse #{info.container.inspect}"
225
+ return
226
+ end
227
+ if cm = method?(info.container)
228
+ ## Add bogus - canonic_file: active-path
229
+ return [cm, 'bogus', info.position,
230
+ info.position_type]
231
+ else
232
+ return [nil] * 4
233
+ end
234
+ when :file
235
+ ## filename = canonic_file(info.container)
236
+ filename = info.container
237
+ # cm =
238
+ # if canonic_file(@frame.file) == filename
239
+ # cm = @frame.method
240
+ # if :line == info.position_type
241
+ # find_method_with_line(cm, info.position)
242
+ # end
243
+ # else
244
+ # LineCache.compiled_method(filename)
245
+ # end
246
+ return nil, filename, info.position, info.position_type
247
+ when nil
248
+ if [:line, :offset].member?(info.position_type)
249
+ ## filename = @frame.file
250
+ # cm = @frame.method
251
+ # if :line == info.position_type
252
+ # cm = find_method_with_line(cm, info.position)
253
+ # end
254
+ return [nil, nil, info.position, info.position_type]
255
+ elsif !info.position_type
256
+ errmsg "Can't parse #{arg} as a position"
257
+ return [nil] * 4
258
+ else
259
+ errmsg "Unknown position type #{info.position_type} for location #{arg}"
260
+ return [nil] * 4
261
+ end
262
+ else
263
+ errmsg "Unknown container type #{info.container_type} for location #{arg}"
264
+ return [nil] * 4
265
+ end
266
+ end
267
+
268
+ def parse_method(meth_str)
269
+ begin
270
+ meth_for_string(meth_str, @frame.binding)
271
+ rescue NameError
272
+ nil
273
+ rescue
274
+ nil
275
+ end
276
+ end
277
+
278
+ def validate_initialize
279
+ ## top_srcdir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
280
+ ## @dbgr_script_iseqs, @dbgr_iseqs = filter_scripts(top_srcdir)
281
+ @file_exists_proc = Proc.new {|filename|
282
+ if LineCache.cached?(filename) || LineCache.cached_script?(filename) ||
283
+ (File.readable?(filename) && !File.directory?(filename))
284
+ true
285
+ ## else
286
+ ## find_load_path(filename)
287
+ end
288
+ }
289
+ end
290
+ end
291
+
292
+ if __FILE__ == $0
293
+ # Demo it.
294
+ # FIXME have to pull in main for its initalize routine
295
+ DIRNAME = File.dirname(__FILE__)
296
+ load File.join(DIRNAME, 'main.rb')
297
+
298
+ require_relative 'mock'
299
+ dbgr, cmd = MockDebugger::setup('exit', false)
300
+ cmdproc = cmd.proc
301
+ onoff = %w(1 0 on off)
302
+ onoff.each { |val| puts "onoff(#{val}) = #{cmdproc.get_onoff(val)}" }
303
+ cmdproc.frame.instance_variable_set('@binding', binding)
304
+ %w(1 1E bad 1+1 -5).each do |val|
305
+ puts "get_int_noerr(#{val}) = #{cmdproc.get_int_noerr(val).inspect}"
306
+ end
307
+ def foo; 5 end
308
+ def cmdproc.errmsg(msg)
309
+ puts msg
310
+ end
311
+
312
+ pos = cmdproc.parse_position('../../rubies/rbx-head/bin/irb')
313
+ puts pos.inspect
314
+
315
+ puts cmdproc.parse_position(__FILE__).inspect
316
+ puts cmdproc.parse_position('8').inspect
317
+ puts cmdproc.parse_position("#{__FILE__} #{__LINE__}").inspect
318
+ # require 'ruby-debug'; Debugger.start; debugger
319
+ p cmdproc.breakpoint_position('../app/display.rb:24', false)
320
+
321
+ puts "To be continued...."
322
+ exit
323
+
324
+ cmdproc.method?('cmdproc.errmsg')
325
+ puts '=' * 40
326
+ ['Array.map', 'Trepan::CmdProcessor.new',
327
+ 'foo', 'cmdproc.errmsg'].each do |str|
328
+ puts "#{str} should be true: #{cmdproc.method?(str).inspect}"
329
+ end
330
+ puts '=' * 40
331
+
332
+ # FIXME:
333
+ # Array#foo should be false: true
334
+ # Trepan::CmdProcessor.allocate should be false: true
335
+
336
+ ['food', '.errmsg'].each do |str|
337
+ puts "#{str} should be false: #{cmdproc.method?(str).inspect}"
338
+ end
339
+ puts '-' * 20
340
+
341
+ puts "Trepan::CmdProcessor.allocate is: #{cmdproc.get_method('Trepan::CmdProcessor.allocate')}"
342
+
343
+ # require_relative '../lib/trepanning'; debugger
344
+ # pos = cmdproc.breakpoint_position('../processor/validate.rb', true)
345
+ # p ['breakpoint validate', pos]
346
+
347
+ p cmdproc.breakpoint_position('foo', true)
348
+ p cmdproc.breakpoint_position("#{__LINE__}", true)
349
+ p cmdproc.breakpoint_position("#{__FILE__}:#{__LINE__}", true)
350
+ p cmdproc.breakpoint_position("#{__FILE__} #{__LINE__} if 1 == a", true)
351
+ puts cmdproc.breakpoint_position("cmdproc.errmsg", false)
352
+ ### p cmdproc.breakpoint_position(%w(2 if a > b))
353
+ p cmdproc.get_int_list(%w(1+0 3-1 3))
354
+ p cmdproc.get_int_list(%w(a 2 3))
355
+ end