trepanning 0.0.4

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 (219) hide show
  1. data/ChangeLog +4422 -0
  2. data/LICENSE +23 -0
  3. data/NEWS +12 -0
  4. data/README.textile +56 -0
  5. data/Rakefile +171 -0
  6. data/app/Makefile +7 -0
  7. data/app/breakpoint.rb +157 -0
  8. data/app/brkptmgr.rb +149 -0
  9. data/app/condition.rb +22 -0
  10. data/app/core.rb +203 -0
  11. data/app/default.rb +54 -0
  12. data/app/disassemble.rb +61 -0
  13. data/app/display.rb +148 -0
  14. data/app/file.rb +135 -0
  15. data/app/frame.rb +275 -0
  16. data/app/irb.rb +112 -0
  17. data/app/mock.rb +22 -0
  18. data/app/options.rb +122 -0
  19. data/app/run.rb +95 -0
  20. data/app/thread.rb +24 -0
  21. data/app/util.rb +32 -0
  22. data/bin/trepan +63 -0
  23. data/data/custom_require.rb +44 -0
  24. data/data/irbrc +55 -0
  25. data/data/prelude.rb +38 -0
  26. data/interface/base_intf.rb +95 -0
  27. data/interface/script.rb +103 -0
  28. data/interface/user.rb +90 -0
  29. data/io/base_io.rb +92 -0
  30. data/io/input.rb +111 -0
  31. data/io/string_array.rb +155 -0
  32. data/lib/Makefile +7 -0
  33. data/lib/trepanning.rb +277 -0
  34. data/processor/breakpoint.rb +108 -0
  35. data/processor/command/alias.rb +55 -0
  36. data/processor/command/backtrace.rb +95 -0
  37. data/processor/command/base/cmd.rb +97 -0
  38. data/processor/command/base/subcmd.rb +207 -0
  39. data/processor/command/base/submgr.rb +178 -0
  40. data/processor/command/base/subsubcmd.rb +102 -0
  41. data/processor/command/base/subsubmgr.rb +182 -0
  42. data/processor/command/break.rb +85 -0
  43. data/processor/command/condition.rb +64 -0
  44. data/processor/command/continue.rb +61 -0
  45. data/processor/command/debug.rb +85 -0
  46. data/processor/command/delete.rb +54 -0
  47. data/processor/command/directory.rb +43 -0
  48. data/processor/command/disable.rb +65 -0
  49. data/processor/command/disassemble.rb +103 -0
  50. data/processor/command/display.rb +81 -0
  51. data/processor/command/down.rb +56 -0
  52. data/processor/command/enable.rb +43 -0
  53. data/processor/command/exit.rb +54 -0
  54. data/processor/command/finish.rb +81 -0
  55. data/processor/command/frame.rb +117 -0
  56. data/processor/command/help.rb +146 -0
  57. data/processor/command/info.rb +28 -0
  58. data/processor/command/info_subcmd/args.rb +56 -0
  59. data/processor/command/info_subcmd/breakpoints.rb +162 -0
  60. data/processor/command/info_subcmd/file.rb +162 -0
  61. data/processor/command/info_subcmd/frame.rb +39 -0
  62. data/processor/command/info_subcmd/iseq.rb +83 -0
  63. data/processor/command/info_subcmd/locals.rb +88 -0
  64. data/processor/command/info_subcmd/program.rb +54 -0
  65. data/processor/command/info_subcmd/registers.rb +72 -0
  66. data/processor/command/info_subcmd/registers_subcmd/dfp.rb +38 -0
  67. data/processor/command/info_subcmd/registers_subcmd/helper.rb +40 -0
  68. data/processor/command/info_subcmd/registers_subcmd/lfp.rb +54 -0
  69. data/processor/command/info_subcmd/registers_subcmd/pc.rb +44 -0
  70. data/processor/command/info_subcmd/registers_subcmd/sp.rb +75 -0
  71. data/processor/command/info_subcmd/return.rb +40 -0
  72. data/processor/command/info_subcmd/thread.rb +106 -0
  73. data/processor/command/irb.rb +106 -0
  74. data/processor/command/kill.rb +58 -0
  75. data/processor/command/list.rb +327 -0
  76. data/processor/command/macro.rb +65 -0
  77. data/processor/command/next.rb +89 -0
  78. data/processor/command/nocache.rb +33 -0
  79. data/processor/command/print.rb +37 -0
  80. data/processor/command/ps.rb +40 -0
  81. data/processor/command/quit.rb +62 -0
  82. data/processor/command/raise.rb +47 -0
  83. data/processor/command/reload.rb +28 -0
  84. data/processor/command/reload_subcmd/command.rb +34 -0
  85. data/processor/command/restart.rb +57 -0
  86. data/processor/command/save.rb +60 -0
  87. data/processor/command/set.rb +47 -0
  88. data/processor/command/set_subcmd/auto.rb +27 -0
  89. data/processor/command/set_subcmd/auto_subcmd/eval.rb +67 -0
  90. data/processor/command/set_subcmd/auto_subcmd/irb.rb +49 -0
  91. data/processor/command/set_subcmd/auto_subcmd/list.rb +51 -0
  92. data/processor/command/set_subcmd/basename.rb +39 -0
  93. data/processor/command/set_subcmd/debug.rb +27 -0
  94. data/processor/command/set_subcmd/debug_subcmd/dbgr.rb +49 -0
  95. data/processor/command/set_subcmd/debug_subcmd/except.rb +35 -0
  96. data/processor/command/set_subcmd/debug_subcmd/macro.rb +35 -0
  97. data/processor/command/set_subcmd/debug_subcmd/skip.rb +35 -0
  98. data/processor/command/set_subcmd/debug_subcmd/stack.rb +45 -0
  99. data/processor/command/set_subcmd/different.rb +67 -0
  100. data/processor/command/set_subcmd/events.rb +71 -0
  101. data/processor/command/set_subcmd/max.rb +35 -0
  102. data/processor/command/set_subcmd/max_subcmd/list.rb +50 -0
  103. data/processor/command/set_subcmd/max_subcmd/stack.rb +60 -0
  104. data/processor/command/set_subcmd/max_subcmd/string.rb +53 -0
  105. data/processor/command/set_subcmd/max_subcmd/width.rb +50 -0
  106. data/processor/command/set_subcmd/return.rb +66 -0
  107. data/processor/command/set_subcmd/sp.rb +62 -0
  108. data/processor/command/set_subcmd/substitute.rb +25 -0
  109. data/processor/command/set_subcmd/substitute_subcmd/eval.rb +98 -0
  110. data/processor/command/set_subcmd/substitute_subcmd/path.rb +55 -0
  111. data/processor/command/set_subcmd/substitute_subcmd/string.rb +72 -0
  112. data/processor/command/set_subcmd/timer.rb +68 -0
  113. data/processor/command/set_subcmd/trace.rb +43 -0
  114. data/processor/command/set_subcmd/trace_subcmd/buffer.rb +56 -0
  115. data/processor/command/set_subcmd/trace_subcmd/print.rb +54 -0
  116. data/processor/command/set_subcmd/trace_subcmd/var.rb +61 -0
  117. data/processor/command/show.rb +27 -0
  118. data/processor/command/show_subcmd/alias.rb +50 -0
  119. data/processor/command/show_subcmd/args.rb +50 -0
  120. data/processor/command/show_subcmd/auto.rb +27 -0
  121. data/processor/command/show_subcmd/auto_subcmd/eval.rb +38 -0
  122. data/processor/command/show_subcmd/auto_subcmd/irb.rb +34 -0
  123. data/processor/command/show_subcmd/auto_subcmd/list.rb +36 -0
  124. data/processor/command/show_subcmd/basename.rb +28 -0
  125. data/processor/command/show_subcmd/debug.rb +27 -0
  126. data/processor/command/show_subcmd/debug_subcmd/dbgr.rb +31 -0
  127. data/processor/command/show_subcmd/debug_subcmd/except.rb +33 -0
  128. data/processor/command/show_subcmd/debug_subcmd/macro.rb +32 -0
  129. data/processor/command/show_subcmd/debug_subcmd/skip.rb +33 -0
  130. data/processor/command/show_subcmd/debug_subcmd/stack.rb +32 -0
  131. data/processor/command/show_subcmd/different.rb +37 -0
  132. data/processor/command/show_subcmd/events.rb +40 -0
  133. data/processor/command/show_subcmd/macro.rb +45 -0
  134. data/processor/command/show_subcmd/max.rb +31 -0
  135. data/processor/command/show_subcmd/max_subcmd/list.rb +39 -0
  136. data/processor/command/show_subcmd/max_subcmd/stack.rb +35 -0
  137. data/processor/command/show_subcmd/max_subcmd/string.rb +41 -0
  138. data/processor/command/show_subcmd/max_subcmd/width.rb +36 -0
  139. data/processor/command/show_subcmd/trace.rb +29 -0
  140. data/processor/command/show_subcmd/trace_subcmd/buffer.rb +84 -0
  141. data/processor/command/show_subcmd/trace_subcmd/print.rb +38 -0
  142. data/processor/command/source.rb +74 -0
  143. data/processor/command/step.rb +139 -0
  144. data/processor/command/stepi.rb +63 -0
  145. data/processor/command/unalias.rb +44 -0
  146. data/processor/command/undisplay.rb +63 -0
  147. data/processor/command/up.rb +92 -0
  148. data/processor/default.rb +45 -0
  149. data/processor/display.rb +17 -0
  150. data/processor/eval.rb +88 -0
  151. data/processor/eventbuf.rb +131 -0
  152. data/processor/frame.rb +230 -0
  153. data/processor/help.rb +72 -0
  154. data/processor/hook.rb +128 -0
  155. data/processor/load_cmds.rb +102 -0
  156. data/processor/location.rb +126 -0
  157. data/processor/main.rb +364 -0
  158. data/processor/mock.rb +100 -0
  159. data/processor/msg.rb +26 -0
  160. data/processor/running.rb +170 -0
  161. data/processor/subcmd.rb +159 -0
  162. data/processor/validate.rb +395 -0
  163. data/test/example/fname with blank.rb +1 -0
  164. data/test/example/gcd-xx.rb +18 -0
  165. data/test/example/gcd.rb +19 -0
  166. data/test/example/gcd1.rb +24 -0
  167. data/test/example/null.rb +1 -0
  168. data/test/example/thread1.rb +3 -0
  169. data/test/functional/fn_helper.rb +119 -0
  170. data/test/functional/test-break.rb +87 -0
  171. data/test/functional/test-condition.rb +59 -0
  172. data/test/functional/test-debugger-call-bug.rb +31 -0
  173. data/test/functional/test-delete.rb +71 -0
  174. data/test/functional/test-finish.rb +44 -0
  175. data/test/functional/test-immediate-step-bug.rb +35 -0
  176. data/test/functional/test-next.rb +77 -0
  177. data/test/functional/test-raise.rb +73 -0
  178. data/test/functional/test-return.rb +100 -0
  179. data/test/functional/test-step.rb +274 -0
  180. data/test/functional/test-stepbug.rb +40 -0
  181. data/test/functional/test-trace-var.rb +40 -0
  182. data/test/functional/tmp/b1.rb +5 -0
  183. data/test/functional/tmp/s1.rb +9 -0
  184. data/test/functional/tmp/t2.rb +6 -0
  185. data/test/integration/file-diff.rb +88 -0
  186. data/test/integration/helper.rb +52 -0
  187. data/test/integration/test-fname-with-blank.rb +11 -0
  188. data/test/integration/test-quit.rb +11 -0
  189. data/test/integration/try-test-enable.rb +11 -0
  190. data/test/unit/cmd-helper.rb +44 -0
  191. data/test/unit/test-app-brkpt.rb +30 -0
  192. data/test/unit/test-app-brkptmgr.rb +56 -0
  193. data/test/unit/test-app-disassemble.rb +60 -0
  194. data/test/unit/test-app-file.rb +46 -0
  195. data/test/unit/test-app-frame.rb +49 -0
  196. data/test/unit/test-app-options.rb +60 -0
  197. data/test/unit/test-app-run.rb +19 -0
  198. data/test/unit/test-app-thread.rb +25 -0
  199. data/test/unit/test-app-util.rb +17 -0
  200. data/test/unit/test-base-subcmd.rb +59 -0
  201. data/test/unit/test-bin-trepan.rb +48 -0
  202. data/test/unit/test-cmd-alias.rb +50 -0
  203. data/test/unit/test-cmd-break.rb +80 -0
  204. data/test/unit/test-cmd-endisable.rb +59 -0
  205. data/test/unit/test-cmd-help.rb +100 -0
  206. data/test/unit/test-cmd-kill.rb +47 -0
  207. data/test/unit/test-cmd-quit.rb +26 -0
  208. data/test/unit/test-cmd-step.rb +45 -0
  209. data/test/unit/test-intf-user.rb +45 -0
  210. data/test/unit/test-io-input.rb +26 -0
  211. data/test/unit/test-proc-eval.rb +26 -0
  212. data/test/unit/test-proc-frame.rb +77 -0
  213. data/test/unit/test-proc-help.rb +15 -0
  214. data/test/unit/test-proc-hook.rb +29 -0
  215. data/test/unit/test-proc-load_cmds.rb +40 -0
  216. data/test/unit/test-proc-main.rb +99 -0
  217. data/test/unit/test-proc-validate.rb +90 -0
  218. data/test/unit/test-subcmd-help.rb +48 -0
  219. metadata +358 -0
@@ -0,0 +1,97 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Base class of all commands. Code common to all commands is here.
4
+ # Note: don't end classname with Command (capital C) since main
5
+ # will think this a command name like QuitCommand
6
+ require 'columnize'
7
+
8
+ class Trepan
9
+ class Command
10
+ attr_accessor :core, :proc
11
+
12
+ unless defined?(MIN_ARGS)
13
+ MIN_ARGS = 0 # run()'s args array must be at least this many
14
+ MAX_ARGS = nil # run()'s args array must be at least this many
15
+ NEED_STACK = false # We'll say that commands which need a stack
16
+ # to run have to declare that and those that
17
+ # don't don't have to mention it.
18
+ end
19
+
20
+ def initialize(proc)
21
+ @name = my_const(:NAME)
22
+ @proc = proc
23
+ end
24
+
25
+ def category
26
+ my_const(:CATEGORY)
27
+ end
28
+
29
+ # List commands arranged in an aligned columns
30
+ def columnize_commands(commands)
31
+ width = settings[:maxwidth]
32
+ Columnize::columnize(commands, width, ' ' * 4,
33
+ true, true, ' ' * 2).chomp
34
+ end
35
+
36
+ def columnize_numbers(commands)
37
+ width = settings[:maxwidth]
38
+ Columnize::columnize(commands, width, ', ',
39
+ false, false, ' ' * 2).chomp
40
+ end
41
+
42
+ # FIXME: probably there is a way to do the delegation to proc methods
43
+ # without having type it all out.
44
+
45
+ def confirm(message, default)
46
+ @proc.confirm(message, default)
47
+ end
48
+
49
+ def errmsg(message)
50
+ @proc.errmsg(message)
51
+ end
52
+
53
+ def obj_const(obj, name)
54
+ obj.class.const_get(name)
55
+ end
56
+
57
+ def msg(message)
58
+ @proc.msg(message)
59
+ end
60
+
61
+ # Convenience short-hand for @dbgr.intf[-1].msg_nocr
62
+ def msg_nocr(msg)
63
+ @proc.msg_nocr(msg)
64
+ end
65
+
66
+ def my_const(name)
67
+ # Set class constant SHORT_HELP to be the first line of HELP
68
+ # unless it has been defined in the class already.
69
+ # The below was the simplest way I could find to do this since
70
+ # we are the super class but want to set the subclass's constant.
71
+ # defined? didn't seem to work here.
72
+ c = self.class.constants
73
+ if c.member?(:HELP) and !c.member?(:SHORT_HELP)
74
+ short_help = self.class.const_get(:HELP).split("\n")[0].chomp('.')
75
+ self.class.const_set(:SHORT_HELP, short_help)
76
+ end
77
+ self.class.const_get(name)
78
+ end
79
+
80
+ # The method that implements the debugger command.
81
+ def run(*args)
82
+ raise RuntimeError, 'You need to define this method elsewhere'
83
+ end
84
+
85
+ def settings
86
+ @proc.settings
87
+ end
88
+
89
+ def short_help
90
+ help_constant_sym = if self.class.constants.member?(:SHORT_HELP)
91
+ :SHORT_HELP
92
+ else :HELP
93
+ end
94
+ my_const(help_constant_sym)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,207 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # A base class for debugger subcommands.
4
+ #
5
+ # Note: don't end classname with Command (capital C) since main
6
+ # will think this a command name like QuitCommand
7
+ # ^
8
+
9
+ # Base Class for Trepan subcommands. We pull in some helper
10
+ # functions for command from module cmdfns.
11
+
12
+ require_relative 'cmd'
13
+
14
+ class Trepan
15
+
16
+ class Subcommand < Command
17
+
18
+ NotImplementedMessage =
19
+ "This method must be overridden in a subclass" unless
20
+ defined?(NotImplementedMessage)
21
+
22
+ attr_reader :name
23
+
24
+ unless defined?(IN_LIST)
25
+ IN_LIST = true # Show item in help list of commands
26
+ RUN_CMD = true # Run subcommand for those subcommands like "show"
27
+ # which append current settings to list output.
28
+ MIN_ABBREV = 1
29
+ NEED_STACK = false
30
+ NAME = 'your_command_name'
31
+ end
32
+
33
+
34
+ # cmd contains the command object that this
35
+ # command is invoked through. A debugger field gives access to
36
+ # the stack frame and I/O.
37
+ def initialize(cmd)
38
+ @cmd = cmd
39
+
40
+ # Convenience class access. We don't expect that any of these
41
+ # will change over the course of the program execution like
42
+ # errmsg(), msg(), and msg_nocr() might. (See the note below
43
+ # on these latter 3 methods.)
44
+ #
45
+ @core = cmd.core
46
+ @proc = cmd.proc
47
+ # @dbgr = cmd.dbgr
48
+
49
+ # By default the name of the subcommand will be the name of the
50
+ # last part of module (e.g. "args" in "info.args" or "basename"
51
+ # in "shows.basename"). However it *is* possible for one to change
52
+ # that -- perhaps one may want to put several subcommands into
53
+ # a single file. So in those cases, one will have to set @name
54
+ # accordingly by other means.
55
+ @name = my_const(:NAME).to_sym
56
+
57
+ end
58
+
59
+ # Convenience short-hand for @proc.confirm
60
+ def confirm(msg, default=false)
61
+ return(@proc.confirm(msg, default))
62
+ end
63
+
64
+ # Set a Boolean-valued debugger setting.
65
+ def run_set_bool(args, default=true)
66
+ onoff_arg = args.size < 3 ? 'on' : args[2]
67
+ begin
68
+ settings[subcmd_setting_key] = @proc.get_onoff(onoff_arg)
69
+ run_show_bool
70
+ rescue NameError, TypeError
71
+ end
72
+ end
73
+
74
+ # set an Integer-valued debugger setting.
75
+ def run_set_int(arg, msg_on_error, min_value=nil, max_value=nil)
76
+ if arg.strip.empty?
77
+ errmsg('You need to supply a number.')
78
+ return
79
+ end
80
+ val = @proc.get_an_int(arg,
81
+ :max_value => max_value,
82
+ :min_value => min_value,
83
+ :msg_on_error => msg_on_error
84
+ )
85
+ if val
86
+ settings[subcmd_setting_key] = val
87
+ run_show_int
88
+ end
89
+ end
90
+
91
+ # Generic subcommand showing a boolean-valued debugger setting.
92
+ def run_show_bool(what=nil)
93
+ val = show_onoff(settings[subcmd_setting_key])
94
+ what = @name unless what
95
+ msg("%s is %s." % [what, val])
96
+ end
97
+
98
+ # Generic subcommand integer value display
99
+ def run_show_int(what=nil)
100
+ val = settings[subcmd_setting_key]
101
+ what = self.class.const_get(:PREFIX)[1..-1].join(' ') unless what
102
+ msg("%s is %d." % [what, val])
103
+ end
104
+
105
+ # Generic subcommand value display. Pass in a hash which may
106
+ # which optionally contain:
107
+ #
108
+ # :name - the String name of key in settings to use. If :value
109
+ # (described below) is set, then setting :name does
110
+ # nothing.
111
+ #
112
+ # :what - the String name of what we are showing. If none is
113
+ # given, then we use the part of the SHORT_HELP string.
114
+ #
115
+ # :value - a String value associated with "what" above. If none
116
+ # is given, then we pick up the value from settings.
117
+ #
118
+ def run_show_val(opts={})
119
+ what = opts.member?(:what) ? opts[:what] : string_in_show
120
+ name = opts.member?(:name) ? opts[:name] : @name
121
+ val = opts.member?(:value) ? opts[:value] : settings[name]
122
+ msg("%s is %s." % [what, val])
123
+ end
124
+
125
+ def save_command_from_settings
126
+ ["#{subcmd_prefix_string} #{settings[subcmd_setting_key]}"]
127
+ end
128
+
129
+ def settings
130
+ @proc.settings
131
+ end
132
+
133
+ def subcmd_prefix_string
134
+ self.class.const_get(:PREFIX).join(' ')
135
+ end
136
+
137
+ def subcmd_setting_key
138
+ self.class.const_get(:PREFIX)[1..-1].join('').to_sym
139
+ end
140
+
141
+ # Return 'on' for true and 'off' for false, and ?? for anything else.
142
+ def show_onoff(bool)
143
+ case(bool)
144
+ when true; return 'on'
145
+ when false; return 'off'
146
+ when nil; return 'unset'
147
+ else return '??'
148
+ end
149
+ end
150
+
151
+ def string_in_show
152
+ my_const(:SHORT_HELP)['Show '.size .. -1].capitalize
153
+ end
154
+
155
+ def summary_help(subcmd_name)
156
+ msg_nocr("%-12s: %s" % [subcmd_name, my_const(:SHORT_HELP)])
157
+ end
158
+
159
+ end
160
+
161
+ class SetBoolSubcommand < Subcommand
162
+ def run(args)
163
+ run_set_bool(args)
164
+ end
165
+
166
+ def save_command
167
+ val = settings[subcmd_setting_key] ? 'on' : 'off'
168
+ ["#{subcmd_prefix_string} #{val}"]
169
+ end
170
+ end
171
+
172
+ class ShowBoolSubcommand < Subcommand
173
+ def run(args)
174
+ run_show_bool(string_in_show)
175
+ end
176
+ end
177
+
178
+ class ShowIntSubcommand < Subcommand
179
+ def run(args)
180
+ if self.respond_to?(:short_help)
181
+ doc = short_help
182
+ else
183
+ doc = my_const(:HELP)[5..-2].capitalize
184
+ end
185
+ run_show_int(doc)
186
+ end
187
+ end
188
+
189
+ end
190
+
191
+ if __FILE__ == $0
192
+ # Demo it.
193
+ require_relative '../../mock'
194
+ dbgr = MockDebugger::MockDebugger.new
195
+ cmds = dbgr.core.processor.commands
196
+ p cmds.keys
197
+ subcmd = Trepan::Subcommand.new(cmds['exit'])
198
+ def subcmd.msg(message)
199
+ puts message
200
+ end
201
+ def subcmd.errmsg(message)
202
+ puts message
203
+ end
204
+ p subcmd.settings
205
+ p subcmd.show_onoff(subcmd.settings[:autoeval])
206
+ subcmd.run_set_int('', 'Just a test')
207
+ end
@@ -0,0 +1,178 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ require_relative 'cmd'
4
+ require_relative '../../subcmd'
5
+ require_relative '../../help'
6
+
7
+ class Trepan::SubcommandMgr < Trepan::Command
8
+
9
+ include Trepan::Help
10
+
11
+ unless defined?(CATEGORY)
12
+ CATEGORY = 'status'
13
+ MIN_ARGS = 0
14
+ MAX_ARGS = nil
15
+ NAME = '?' # FIXME: Need to define this, but should
16
+ # pick this up from class/file name.
17
+ NEED_STACK = false
18
+ end
19
+
20
+ attr_accessor :subcmds # Array of instaniated Trepan::Subcommand objects
21
+ attr_reader :name # Name of command
22
+ attr_reader :last_args # Last arguments seen
23
+
24
+ # Initialize show subcommands. Note: instance variable name
25
+ # has to be setcmds ('set' + 'cmds') for subcommand completion
26
+ # to work.
27
+ def initialize(proc)
28
+ @name = obj_const(self, :NAME)
29
+ @subcmds = Trepan::Subcmd.new(self)
30
+ @proc = proc
31
+ load_debugger_subcommands(@name, self)
32
+ end
33
+
34
+ # Create an instance of each of the debugger subcommands. Commands
35
+ # are found by importing files in the directory 'name' + '_sub'. Some
36
+ # files are excluded via an array set in initialize. For each of
37
+ # the remaining files, we import them and scan for class names
38
+ # inside those files and for each class name, we will create an
39
+ # instance of that class. The set of TrepanCommand class instances
40
+ # form set of possible debugger commands.
41
+ def load_debugger_subcommands(name, parent)
42
+
43
+ # Initialization
44
+ cmd_names = []
45
+ subcmd_names = []
46
+ cmd_dir = File.dirname(__FILE__)
47
+ subcmd_dir = File.join(cmd_dir, '..', name + '_subcmd')
48
+ files = Dir.glob(File.join(subcmd_dir, '*.rb'))
49
+ files.each do |rb|
50
+ basename = File.basename(rb, '.rb')
51
+ if File.directory?(File.join(File.dirname(rb), basename + '_subcmd'))
52
+ subcmd_names << name.capitalize + basename.capitalize
53
+ else
54
+ cmd_names << name.capitalize + basename.capitalize
55
+ end
56
+ require rb
57
+ end if File.directory?(subcmd_dir)
58
+
59
+ subcommands = {}
60
+ cmd_names.each do |name|
61
+ next unless Trepan::Subcommand.constants.member?(name.to_sym)
62
+ subcmd_class = "Trepan::Subcommand::#{name}.new(self)"
63
+ cmd = self.instance_eval(subcmd_class)
64
+ cmd_name = cmd.name
65
+ @subcmds.add(cmd)
66
+ end
67
+ subcmd_names.each do |name|
68
+ next unless Trepan::SubSubcommand.constants.member?(name.to_sym)
69
+ subcmd_class = "Trepan::SubSubcommand::#{name}.new(self, parent)"
70
+ begin
71
+ cmd = self.instance_eval(subcmd_class)
72
+ rescue
73
+ puts "Subcmd #{name} is bad"
74
+ end
75
+ cmd_name = cmd.name
76
+ @subcmds.add(cmd)
77
+ end
78
+ end
79
+
80
+ # Give help for a command which has subcommands. This can be
81
+ # called in several ways:
82
+ # help cmd
83
+ # help cmd subcmd
84
+ # help cmd commands
85
+ #
86
+ # Our shtick is to give help for the overall command only if
87
+ # subcommand or 'commands' is not given. If a subcommand is given and
88
+ # found, then specific help for that is given. If 'commands' is given
89
+ # we will list the all the subcommands.
90
+ def help(args)
91
+ if args.size <= 2
92
+ # "help cmd". Give the general help for the command part.
93
+ doc = my_const(:HELP)
94
+ if doc
95
+ return doc
96
+ else
97
+ errmsg('Sorry - author mess up. ' +
98
+ 'No help registered for command' +
99
+ @name)
100
+ return nil
101
+ end
102
+ end
103
+
104
+ subcmd_name = args[2]
105
+
106
+ if '*' == subcmd_name
107
+ help_text = ["List of subcommands for command '%s':" % @name]
108
+ help_text << columnize_commands(@subcmds.list)
109
+ return help_text
110
+ end
111
+
112
+ # "help cmd subcmd". Give help specific for that subcommand.
113
+ cmd = @subcmds.lookup(subcmd_name, false)
114
+ if cmd
115
+ if cmd.respond_to?(:help)
116
+ return cmd.help(args)
117
+ else
118
+ doc = obj_const(cmd, :HELP)
119
+ if doc
120
+ return doc
121
+ else
122
+ errmsg('Sorry - author mess up. ' +
123
+ 'No help registered for subcommand: ' +
124
+ subcmd_name + ', of command: ' +
125
+ @name)
126
+ return nil
127
+ end
128
+ end
129
+ else
130
+ matches = @subcmds.list.grep(/^#{subcmd_name}/).sort
131
+ if matches.empty?
132
+ errmsg("No #{name} subcommands found matching /^#{subcmd_name}/. Try \"help\" #{@name}.")
133
+ return nil
134
+ elsif 1 == matches.size
135
+ args[-1] = matches[0].to_s
136
+ help(args)
137
+ else
138
+ help_text = ["Subcommands of \"#{@name}\" matching /^#{subcmd_name}/:"]
139
+ help_text << columnize_commands(matches.sort)
140
+ return help_text
141
+ end
142
+ end
143
+ end
144
+
145
+ def run(args)
146
+ @last_args = args
147
+ if args.size < 2 || args.size == 2 && args[-1] == '*'
148
+ summary_list(obj_const(self, :NAME), @subcmds)
149
+ return false
150
+ end
151
+
152
+ subcmd_prefix = args[1]
153
+ # We were given: cmd subcmd ...
154
+ # Run that.
155
+ subcmd = @subcmds.lookup(subcmd_prefix)
156
+ if subcmd
157
+ subcmd.run(args)
158
+ else
159
+ undefined_subcmd(@name, subcmd_prefix)
160
+ end
161
+ end
162
+ end
163
+
164
+ if __FILE__ == $0
165
+ # Demo it.
166
+ require_relative '../../mock'
167
+ dbgr = MockDebugger::MockDebugger.new
168
+ cmds = dbgr.core.processor.commands
169
+ cmd = cmds['set']
170
+ Trepan::SubcommandMgr.new(dbgr.core.processor)
171
+ puts cmd.help(%w(help set))
172
+ puts '=' * 40
173
+ # require_relative '../../../lib/trepanning)
174
+ # Trepan.debug(:set_restart => true)
175
+ puts cmd.help(%w(help set *))
176
+ puts '=' * 40
177
+ puts cmd.help(%w(help set d.*))
178
+ end
@@ -0,0 +1,102 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # A base class for debugger subcommands of subcommands.
4
+ #
5
+ # Note: don't end classname with Command (capital C as in SubCommand),
6
+ # since main will think this a command name like QuitCommand
7
+ # ^
8
+
9
+ # Base Class for Trepan subcommands. We pull in some helper
10
+ # functions for command from module cmdfns.
11
+
12
+ require_relative 'cmd'
13
+ require_relative 'subcmd'
14
+
15
+ class Trepan
16
+
17
+ class SubSubcommand < Subcommand
18
+ def initialize(cmd, parent, name)
19
+ @cmd = cmd
20
+ @name = name
21
+ @parent = parent
22
+ @proc = parent.proc
23
+ end
24
+
25
+ def settings
26
+ @parent.settings
27
+ end
28
+
29
+ def string_in_show
30
+ help_constant_sym = if self.class.constants.member?(:SHORT_HELP)
31
+ :SHORT_HELP
32
+ else :HELP
33
+ end
34
+ str = my_const(help_constant_sym)
35
+ %w(Show Set).each do |word|
36
+ if 0 == str.index(word)
37
+ str = str[word.size+1 ..-1].capitalize
38
+ break
39
+ end
40
+ end
41
+ str
42
+ end
43
+
44
+ # Set a Boolean-valued debugger setting.
45
+ def run_set_bool(args, default=true)
46
+ set_val = args.size < 2 ? 'on' : args[1]
47
+ setting = @name.gsub(/^(set|show)/,'')
48
+ begin
49
+ settings[setting.to_sym] = @proc.get_onoff(set_val)
50
+ run_show_bool(string_in_show)
51
+ rescue NameError, TypeError
52
+ end
53
+ end
54
+
55
+ def run_show_bool(what=nil)
56
+ setting = @name.gsub(/^(set|show)/,'')
57
+ val = show_onoff(settings[setting.to_sym])
58
+ what = setting unless what
59
+ msg('%s is %s.' % [what.chomp, val])
60
+ end
61
+
62
+ end
63
+
64
+ class SetBoolSubSubcommand < SubSubcommand
65
+ def run(args)
66
+ run_set_bool(args)
67
+ end
68
+
69
+ def save_command
70
+ val = settings[subcmd_setting_key] ? 'on' : 'off'
71
+ ["#{subcmd_prefix_string} #{val}"]
72
+ end
73
+ end
74
+
75
+ class ShowBoolSubSubcommand < SubSubcommand
76
+ def run(args)
77
+ run_show_bool(string_in_show)
78
+ end
79
+ end
80
+
81
+ class ShowIntSubSubcommand < SubSubcommand
82
+ def run(args)
83
+ run_show_int
84
+ end
85
+ end
86
+ end
87
+
88
+ if __FILE__ == $0
89
+ # Demo it.
90
+ require_relative '../../mock'
91
+ require_relative '../../subcmd'
92
+ name = File.basename(__FILE__, '.rb')
93
+
94
+ # FIXME: DRY the below code
95
+ dbgr, info_cmd = MockDebugger::setup('info')
96
+ testcmdMgr = Trepan::Subcmd.new(info_cmd)
97
+ cmd_name = 'testing'
98
+ infox_cmd = Trepan::SubSubcommand.new(info_cmd.proc,
99
+ info_cmd,
100
+ cmd_name)
101
+ infox_cmd.settings
102
+ end