rb8-trepanning 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +52 -0
  274. metadata +391 -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