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
data/processor/help.rb ADDED
@@ -0,0 +1,92 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ module Trepan
3
+ # class SubHelp
4
+ # def initialize(name, dir)
5
+ # @name = name
6
+ # @dir = dir
7
+ # load_sub_help_files(dir)
8
+ # end
9
+
10
+ # def load_sub_help_files(dir)
11
+ # Dir.glob(dir, '*.txt').each do |txt|
12
+ # basename = File.basename(txt, '.txt')
13
+ # @list << basename
14
+ # end
15
+ # end if File.directory?(dir)
16
+
17
+ # def summary_help
18
+ # section "List of #{@name} help"
19
+ # msg @list
20
+ # end
21
+ # end
22
+
23
+ module Help
24
+
25
+ def abbrev_stringify(name, min_abbrev)
26
+ "(#{name[0..min_abbrev-1]})#{name[min_abbrev..-1]}"
27
+ end
28
+
29
+ def summary_help(subcmd)
30
+ # Set class constant SHORT_HELP to be the first line of HELP
31
+ # unless it has been defined in the class already.
32
+ # The below was the simplest way I could find to do this since
33
+ # we are the super class but want to set the subclass's constant.
34
+ # defined? didn't seem to work here.
35
+ c = subcmd.class.constants
36
+ if c.member?('HELP') and !c.member?('SHORT_HELP')
37
+ short_help = subcmd.class.const_get('HELP').split("\n")[0].chomp('.')
38
+ subcmd.class.const_set(:SHORT_HELP, short_help)
39
+ end
40
+
41
+ ' %-12s -- %s' %
42
+ [abbrev_stringify(obj_const(subcmd, :NAME),
43
+ obj_const(subcmd, :MIN_ABBREV)),
44
+ obj_const(subcmd, :SHORT_HELP)]
45
+ end
46
+
47
+ # We were given cmd without a subcommand; cmd is something
48
+ # like "show", "info" or "set". Generally this means list
49
+ # all of the subcommands.
50
+ def summary_list(name, subcmds)
51
+ msg "List of #{name} commands (with minimum abbreviation in parenthesis):"
52
+ subcmds.list.each do |subcmd_name|
53
+ # Some commands have lots of output.
54
+ # they are excluded here because 'in_list' is false.
55
+ msg summary_help(subcmds.subcmds[subcmd_name])
56
+ end
57
+ end
58
+
59
+
60
+ # Error message when subcommand asked for but doesn't exist
61
+ def undefined_subcmd(cmd, subcmd)
62
+ errmsg(('Undefined "%s" subcommand: "%s". ' +
63
+ "Try \"help %s *.\"") % [cmd, subcmd, cmd])
64
+ end
65
+
66
+ end
67
+ end
68
+
69
+ if __FILE__ == $0
70
+ class TestClass
71
+ include Trepan::Help
72
+ HELP = 'TestClass HELP.
73
+
74
+ Long description goes here.'
75
+ MIN_ABBREV = 1
76
+ NAME = File.basename(__FILE__)
77
+ def obj_const(obj, name)
78
+ obj.class.const_get(name)
79
+ end
80
+ def msg(mess)
81
+ puts mess
82
+ end
83
+ def errmsg(mess)
84
+ puts "***#{mess}"
85
+ end
86
+ def initialize
87
+ puts summary_help(self)
88
+ undefined_subcmd('foo', 'bar')
89
+ end
90
+ end
91
+ TestClass.new
92
+ end
@@ -0,0 +1,76 @@
1
+ module Trepan
2
+
3
+ def inside_emacs?
4
+ ENV['EMACS'] || ENV['INSIDE_EMACS']
5
+ end
6
+ module_function :inside_emacs?
7
+
8
+ module ParseFunctions
9
+ Position_regexp = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))' unless
10
+ defined? Position_regexp
11
+
12
+
13
+ # Parse 'str' of command 'cmd' as an integer between
14
+ # min and max. If either min or max is nil, that
15
+ # value has no bound.
16
+ def get_int(str, cmd, min=nil, max=nil, default=1)
17
+ return default unless str
18
+ begin
19
+ int = Integer(str)
20
+ if min and int < min
21
+ print "%s argument '%s' needs to at least %s.\n" % [cmd, str, min]
22
+ return nil
23
+ elsif max and int > max
24
+ print "%s argument '%s' needs to at most %s.\n" % [cmd, str, max]
25
+ return nil
26
+ end
27
+ return int
28
+ rescue
29
+ print "%s argument '%s' needs to be a number.\n" % [cmd, str]
30
+ return nil
31
+ end
32
+ end
33
+
34
+ # Return true if arg is 'on' or 1 and false arg is 'off' or 0.
35
+ # Any other value raises RuntimeError.
36
+ def get_onoff(arg, default=nil, print_error=true)
37
+ if arg.nil? or arg == ''
38
+ if default.nil?
39
+ if print_error
40
+ print "Expecting 'on', 1, 'off', or 0. Got nothing.\n"
41
+ raise RuntimeError
42
+ end
43
+ return default
44
+ end
45
+ end
46
+ case arg.downcase
47
+ when '1', 'on'
48
+ return true
49
+ when '0', 'off'
50
+ return false
51
+ else
52
+ if print_error
53
+ print "Expecting 'on', 1, 'off', or 0. Got: %s.\n" % arg.to_s
54
+ raise RuntimeError
55
+ end
56
+ end
57
+ end
58
+
59
+ # Return 'on' or 'off' for supplied parameter. The parmeter should
60
+ # be true, false or nil.
61
+ def show_onoff(bool)
62
+ if not [TrueClass, FalseClass, NilClass].member?(bool.class)
63
+ return "??"
64
+ end
65
+ return bool ? 'on' : 'off'
66
+ end
67
+
68
+ # Return true if code is syntactically correct for Ruby.
69
+ def syntax_valid?(code)
70
+ eval("BEGIN {return true}\n#{code}", nil, "", 0)
71
+ rescue Exception
72
+ false
73
+ end
74
+
75
+ end
76
+ end
data/processor/hook.rb ADDED
@@ -0,0 +1,134 @@
1
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
2
+ require 'rubygems'; require 'require_relative'
3
+ require_relative 'virtual'
4
+
5
+ class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
6
+ # Command processor hooks.
7
+ attr_reader :autodis_hook
8
+ attr_reader :autoirb_hook
9
+ attr_reader :autolist_hook
10
+ attr_reader :debug_dbgr_hook
11
+ attr_reader :display_hook
12
+ attr_reader :timer_hook
13
+ attr_reader :trace_hook
14
+ attr_reader :tracebuf_hook
15
+ attr_reader :unconditional_prehooks
16
+ attr_reader :cmdloop_posthooks
17
+ attr_reader :cmdloop_prehooks
18
+
19
+ # Used to time how long a debugger action takes
20
+ attr_accessor :time_last
21
+
22
+ class Hook
23
+ attr_accessor :list
24
+
25
+ def initialize(list=[])
26
+ @list = list
27
+ end
28
+
29
+ def delete_by_name(delete_name)
30
+ @list.delete_if {|hook_name, priority, hook| hook_name == delete_name}
31
+ end
32
+
33
+ def empty?
34
+ @list.empty?
35
+ end
36
+
37
+ def insert(priority, name, hook)
38
+ insert_loc = @list.size # at end
39
+ @list.each_with_index do |entry, index|
40
+ n, p, h = entry
41
+ if priority > p
42
+ insert_loc = index
43
+ break
44
+ end
45
+ end
46
+ @list.insert(insert_loc, [name, priority, hook])
47
+ end
48
+
49
+ def insert_if_new(priority, name, hook)
50
+ insert(priority, name, hook) unless
51
+ @list.find {|try_name, try_priority, try_hook| try_name == name}
52
+ end
53
+
54
+ # Run each function in `hooks' with args
55
+ def run(*args)
56
+ @list.each do |name, priority, hook|
57
+ hook.call(name, *args)
58
+ end
59
+ end
60
+
61
+ # Could add delete_at and delete if necessary.
62
+ end
63
+
64
+ def hook_initialize(commands)
65
+ @cmdloop_posthooks = Hook.new
66
+ @cmdloop_prehooks = Hook.new
67
+ @unconditional_prehooks = Hook.new
68
+
69
+ irb_cmd = commands['irb']
70
+ @autoirb_hook = ['autoirb',
71
+ Proc.new{|*args| irb_cmd.run(['irb']) if irb_cmd}]
72
+
73
+ @debug_dbgr_hook = ['dbgdbgr',
74
+ Proc.new{|*args|
75
+ if settings[:debugdbgr]
76
+ $trepan_cmdproc = self
77
+ $trepan_frame = @frame
78
+ else
79
+ $trepan_cmdproc = nil
80
+ $trepan_frame = nil
81
+ end}]
82
+
83
+ display_cmd = commands['display']
84
+ @display_hook = ['display',
85
+ Proc.new{|*args| display_cmd.run(['display']) if display_cmd}]
86
+
87
+ # FIXME: generalize for any command run
88
+ dis_cmd = commands['disassemble']
89
+ @autodis_hook = ['autodis',
90
+ Proc.new{|*args| dis_cmd.run(['disassemble']) if dis_cmd}]
91
+
92
+ list_cmd = commands['list']
93
+ @autolist_hook = ['autolist',
94
+ Proc.new{|*args| list_cmd.run(['list']) if list_cmd}]
95
+
96
+ @timer_hook = ['timer',
97
+ Proc.new{|*args|
98
+ now = Time.now
99
+ msg("%g seconds" %
100
+ (now - @time_last)) if @time_last
101
+ @time_last = now
102
+ }]
103
+ @timer_posthook = ['timer', Proc.new{|*args| @time_last = Time.now}]
104
+ @trace_hook = ['trace',
105
+ Proc.new{|*args| print_location}]
106
+ @tracebuf_hook = ['tracebuffer',
107
+ Proc.new{|*args| @eventbuf.append(@event, @frame,
108
+ nil)}]
109
+ end
110
+ end
111
+
112
+ if __FILE__ == $0
113
+ # Demo it.
114
+ hooks = Trepan::CmdProcessor::Hook.new
115
+ hooks.run(5)
116
+ hook1 = Proc.new {|name, a| puts "#{name} called with #{a}"}
117
+ hooks = Trepan::CmdProcessor::Hook.new()
118
+ hooks.insert(-1, 'hook1', hook1)
119
+ p hooks.list
120
+ hooks.insert_if_new(-1, 'hook1', hook1)
121
+ puts '-' * 30
122
+ p hooks.list
123
+ hooks.run(10)
124
+ puts '-' * 30
125
+ hooks.insert(-1, 'hook2', hook1)
126
+ hooks.run(20)
127
+ puts '-' * 30
128
+ hooks.delete_by_name('hook2')
129
+ hooks.run(30)
130
+ puts '-' * 30
131
+ hooks.delete_by_name('hook1')
132
+ hooks.run(30)
133
+ puts '-' * 30
134
+ end
@@ -0,0 +1,258 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010, 2011 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require 'tmpdir'
4
+
5
+ # Part of Trepan::CmdProcess that loads up debugger commands from
6
+ # builtin and user directories.
7
+ # Sets @commands, @aliases, @macros
8
+ require 'rubygems'; require 'require_relative'
9
+ require_relative '../app/complete'
10
+ require_relative 'virtual'
11
+ class Trepan::CmdProcessor < Trepan::VirtualCmdProcessor
12
+
13
+ attr_reader :aliases # Hash[String] of command names
14
+ # indexed by alias name
15
+ attr_reader :commands # Hash[String] of command objects
16
+ # indexed by name
17
+ attr_reader :macros # Hash[String] of Proc objects
18
+ # indexed by macro name.
19
+ attr_reader :leading_str # leading part of string. Used in
20
+ # command completion
21
+
22
+ # "initialize" for multi-file class. Called from main.rb's "initialize".
23
+ def load_cmds_initialize
24
+ @commands = {}
25
+ @aliases = {}
26
+ @macros = {}
27
+
28
+ cmd_dirs = [ File.join(File.dirname(__FILE__), 'command') ]
29
+ cmd_dirs << @settings[:user_cmd_dir] if @settings[:user_cmd_dir]
30
+ cmd_dirs.each do |cmd_dir|
31
+ load_debugger_commands(cmd_dir) if File.directory?(cmd_dir)
32
+ end
33
+ end
34
+
35
+ # Loads in debugger commands by require'ing each ruby file in the
36
+ # 'command' directory. Then a new instance of each class of the
37
+ # form Trepan::xxCommand is added to @commands and that array
38
+ # is returned.
39
+ def load_debugger_commands(file_or_dir)
40
+ if File.directory?(file_or_dir)
41
+ dir = File.expand_path(file_or_dir)
42
+ # change $0 so it doesn't get in the way of __FILE__ = $0
43
+ old_dollar0 = $0
44
+ $0 = ''
45
+ Dir.glob(File.join(dir, '*.rb')).each do |rb|
46
+ # We use require so that multiple calls have no effect.
47
+ require rb
48
+ end
49
+ $0 = old_dollar0
50
+ elsif File.readable?(file_or_dir)
51
+ # We use load in case we are reloading.
52
+ # 'require' would not be effective here
53
+ load file_or_dir
54
+ else
55
+ return false
56
+ end
57
+ # Instantiate each Command class found by the above require(s).
58
+ Trepan::Command.constants.grep(/.Command$/).each do |name|
59
+ klass = Trepan::Command.const_get(name)
60
+ cmd = klass.send(:new, self)
61
+
62
+ # Add to list of commands and aliases.
63
+ cmd_name = klass.const_get(:NAME)
64
+ if klass.constants.member?('ALIASES') ||
65
+ klass.constants.member?(:ALIASES)
66
+ aliases= klass.const_get('ALIASES') || klass.const_get(:ALIASES)
67
+ aliases.each {|a| @aliases[a] = cmd_name}
68
+ end
69
+ @commands[cmd_name] = cmd
70
+ end
71
+ return true
72
+ end
73
+
74
+ def load_debugger_command(command_file)
75
+ return unless File.readable?(command_file)
76
+ load command_file
77
+ Trepan::Command.constants.grep(/.Command$/).each do |command|
78
+ setup_command(command)
79
+ end
80
+ end
81
+
82
+ # Looks up cmd_array[0] in @commands and runs that. We do lots of
83
+ # validity testing on cmd_array.
84
+ def run_cmd(cmd_array)
85
+ unless cmd_array.is_a?(Array)
86
+ errmsg "run_cmd argument should be an Array, got: #{cmd_array.class}"
87
+ return
88
+ end
89
+ if cmd_array.detect{|item| !item.is_a?(String)}
90
+ errmsg "run_cmd argument Array should only contain strings. " +
91
+ "Got #{cmd_array.inspect}"
92
+ return
93
+ end
94
+ if cmd_array.empty?
95
+ errmsg "run_cmd Array should have at least one item. " +
96
+ "Got: #{cmd_array.inspect}"
97
+ return
98
+ end
99
+ cmd_name = cmd_array[0]
100
+ if @commands.member?(cmd_name)
101
+ @commands[cmd_name].run(cmd_array)
102
+ end
103
+ end
104
+
105
+ def save_commands(opts)
106
+ save_filename = opts[:filename] ||
107
+ File.join(Dir.tmpdir, "trepanning-save-#{$$}.txt")
108
+ begin
109
+ save_file = File.open(save_filename, 'w')
110
+ rescue => exc
111
+ errmsg("Can't open #{save_filename} for writing.")
112
+ errmsg("System reports: #{exc.inspect}")
113
+ return nil
114
+ end
115
+ save_file.puts "#\n# Commands to restore trepanning environment\n#\n"
116
+ @commands.each do |cmd_name, cmd_obj|
117
+ cmd_obj.save_command if cmd_obj.respond_to?(:save_command)
118
+ next unless cmd_obj.is_a?(Trepan::SubcommandMgr)
119
+ cmd_obj.subcmds.subcmds.each do |subcmd_name, subcmd_obj|
120
+ save_file.puts subcmd_obj.save_command if
121
+ subcmd_obj.respond_to?(:save_command)
122
+ next unless subcmd_obj.is_a?(Trepan::SubSubcommandMgr)
123
+ subcmd_obj.subcmds.subcmds.each do |subsubcmd_name, subsubcmd_obj|
124
+ save_file.puts subsubcmd_obj.save_command if
125
+ subsubcmd_obj.respond_to?(:save_command)
126
+ end
127
+ end
128
+ end
129
+ save_file.puts "!FileUtils.rm #{save_filename.inspect}" if
130
+ opts[:erase]
131
+ save_file.close
132
+
133
+ return save_filename
134
+ end
135
+
136
+ # Instantiate a Trepan::Command and extract info: the NAME, ALIASES
137
+ # and store the command in @commands.
138
+ def setup_command(command)
139
+ # Note: there is probably a non-eval way to instantiate the
140
+ # command, but I don't know it. And eval works.
141
+ klass = self.instance_eval("Trepan::Command::#{command}")
142
+ cmd = klass.send(:new, self)
143
+
144
+ # Add to list of commands and aliases.
145
+ cmd_name = klass.const_get(:NAME)
146
+ if klass.constants.member?(:ALIASES)
147
+ aliases= klass.const_get(:ALIASES)
148
+ aliases.each {|a| @aliases[a] = cmd_name}
149
+ end
150
+ @commands[cmd_name] = cmd
151
+ end
152
+
153
+ # Handle initial completion. We draw from the commands, aliases,
154
+ # and macros for completion. However we won't include aliases which
155
+ # are prefixes of other commands.
156
+ def complete(str, last_token)
157
+ @leading_str = str
158
+ next_blank_pos, token = Trepan::Complete.next_token(str, 0)
159
+ return [''] if token.empty? && !last_token.empty?
160
+ match_pairs = Trepan::Complete.complete_token_with_next(@commands,
161
+ token)
162
+ match_hash = {}
163
+ match_pairs.each do |pair|
164
+ match_hash[pair[0]] = pair[1]
165
+ end
166
+ alias_pairs = Trepan::Complete.
167
+ complete_token_filtered_with_next(@aliases, token, match_hash,
168
+ @commands)
169
+ match_pairs += alias_pairs
170
+ if str[next_blank_pos..-1].empty?
171
+ return match_pairs.map{|pair| pair[0]}.sort
172
+ else
173
+ alias_pairs.each do |pair|
174
+ match_hash[pair[0]] = pair[1]
175
+ end
176
+ end
177
+ if match_pairs.size > 1
178
+ # FIXME: figure out what to do here.
179
+ # Matched multiple items in the middle of the string
180
+ # We can't handle this so do nothing.
181
+ return []
182
+ # return match_pairs.map do |name, cmd|
183
+ # ["#{name} #{args[1..-1].join(' ')}"]
184
+ # end
185
+ end
186
+ # match_pairs.size == 1
187
+ next_complete(str, next_blank_pos, match_pairs[0][1], last_token)
188
+ end
189
+
190
+ def next_complete(str, next_blank_pos, cmd, last_token)
191
+ next_blank_pos, token = Trepan::Complete.next_token(str, next_blank_pos)
192
+ return [] if token.empty? && !last_token.empty?
193
+
194
+ if cmd.respond_to?(:complete_token_with_next)
195
+ match_pairs = cmd.complete_token_with_next(token)
196
+ return [] if match_pairs.empty?
197
+ if str[next_blank_pos..-1].rstrip.empty? &&
198
+ (token.empty? || token == last_token)
199
+ return match_pairs.map { |completion, junk| completion }
200
+ else
201
+ if match_pairs.size == 1
202
+ return next_complete(str, next_blank_pos, match_pairs[0][1],
203
+ last_token)
204
+ else
205
+ # FIXME: figure out what to do here.
206
+ # Matched multiple items in the middle of the string
207
+ # We can't handle this so do nothing.
208
+ return []
209
+ end
210
+ end
211
+ elsif cmd.respond_to?(:complete)
212
+ matches = cmd.complete(token)
213
+ return [] if matches.empty?
214
+ if str[next_blank_pos..-1].rstrip.empty? &&
215
+ (token.empty? || token == last_token)
216
+ return matches
217
+ else
218
+ # FIXME: figure out what to do here.
219
+ # Matched multiple items in the middle of the string
220
+ # We can't handle this so do nothing.
221
+ return []
222
+ end
223
+ else
224
+ return []
225
+ end
226
+ end
227
+ end
228
+
229
+ if __FILE__ == $0
230
+ require_relative '../interface/user' # user interface (includes I/O)
231
+ cmdproc = Trepan::CmdProcessor.new([], nil)
232
+ cmddir = File.join(File.dirname(__FILE__), 'command')
233
+ cmdproc.instance_variable_set('@settings', {})
234
+ cmdproc.interfaces = [Trepan::UserInterface.new(nil, nil,
235
+ :history_save=>false)]
236
+ cmdproc.load_cmds_initialize
237
+ require 'columnize'
238
+ puts Columnize.columnize(cmdproc.commands.keys.sort)
239
+ puts '=' * 20
240
+ puts Columnize.columnize(cmdproc.aliases.keys.sort)
241
+ puts '=' * 20
242
+
243
+ def cmdproc.errmsg(mess)
244
+ puts "** #{mess}"
245
+ end
246
+
247
+ def cmdproc.msg(mess)
248
+ puts mess
249
+ end
250
+
251
+ cmdproc.run_cmd('foo') # Invalid - not an Array
252
+ cmdproc.run_cmd([]) # Invalid - empty Array
253
+ cmdproc.run_cmd(['list', 5]) # Invalid - nonstring arg
254
+ p cmdproc.complete("d", 'd')
255
+ require 'ruby-debug'; Debugger.start; debugger
256
+ p cmdproc.complete("sho d", 'd')
257
+ p cmdproc.complete('', '')
258
+ end