trepanning 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
data/bin/trepan ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # Invoke debugger from the command line.
4
+ require_relative '../app/run'
5
+ require_relative '../app/options'
6
+ require_relative '../lib/trepanning'
7
+
8
+ # FIXME: the figure out how to run via gem installation.
9
+ if File.basename(__FILE__) == File.basename($0)
10
+ include Trepanning
11
+
12
+ # One way to get local variables is to create a block which is run
13
+ # once.
14
+ #
15
+ # Note however that since there are constants below, we can't
16
+ # wrap all of this in a procedure as that would be defining
17
+ # constants dynamically.
18
+ 1.times do
19
+ | ; trepan_path, program_to_debug |
20
+ # options = DEFAULT_CMDLINE_SETTINGS.merge({}) seems to change up
21
+ # DEFAULT_CMDLINE_SETTINGS when options[:key] is changed. The
22
+ # below is the simplest thing I can come up with so far.
23
+ options = copy_default_options
24
+ opts = setup_options(options)
25
+ Trepan::ARGV = ARGV.clone
26
+ rest = opts.parse! ARGV
27
+
28
+ trepan_path = File.expand_path($0)
29
+ if RUBY_PLATFORM =~ /mswin/
30
+ trepan_path += '.cmd' unless trepan_path =~ /\.cmd$/i
31
+ end
32
+
33
+ # FIXME: do we need to test defined?
34
+ # FIXME: Should (some of) these be instance variables?
35
+ Trepan::RUBY_PATH = ruby_path
36
+ Trepan::TREPAN_PATH = trepan_path
37
+ Trepan::RBDBGR_FILE = __FILE__
38
+
39
+ if ARGV.empty?
40
+ if options[:version] || options[:help]
41
+ exit 100
42
+ else
43
+ STDERR.puts 'Sorry - for now you must specify a Ruby script to debug.'
44
+ exit(1)
45
+ end
46
+ end
47
+
48
+ program_to_debug = ARGV.shift
49
+ program_to_debug = whence_file(program_to_debug) unless
50
+ File.exist?(program_to_debug)
51
+ Trepan::PROG_SCRIPT = program_to_debug
52
+
53
+ # Set global so others may use this debugger.
54
+ $trepan = Trepan.new(:restart_argv =>
55
+ explicit_restart_argv(Trepan::ARGV),
56
+ :cmdfiles => options[:cmdfiles],
57
+ :initial_dir => options[:chdir],
58
+ :nx => options[:nx]
59
+ )
60
+ debug_program($trepan, Trepan::RUBY_PATH,
61
+ File.expand_path(program_to_debug))
62
+ end
63
+ end
@@ -0,0 +1,44 @@
1
+ #--
2
+ # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+ module Kernel
8
+
9
+ ##
10
+ # The Kernel#require from before RubyGems was loaded.
11
+
12
+ alias gem_original_require require
13
+
14
+ ##
15
+ # When RubyGems is required, Kernel#require is replaced with our own which
16
+ # is capable of loading gems on demand.
17
+ #
18
+ # When you call <tt>require 'x'</tt>, this is what happens:
19
+ # * If the file can be loaded from the existing Ruby loadpath, it
20
+ # is.
21
+ # * Otherwise, installed gems are searched for a file that matches.
22
+ # If it's found in gem 'y', that gem is activated (added to the
23
+ # loadpath).
24
+ #
25
+ # The normal <tt>require</tt> functionality of returning false if
26
+ # that file has already been loaded is preserved.
27
+
28
+ def require(path) # :doc:
29
+ gem_original_require path
30
+ rescue LoadError => load_error
31
+ if load_error.message.end_with?(path)
32
+ if Gem.try_activate(path)
33
+ return gem_original_require(path)
34
+ end
35
+ end
36
+
37
+ raise load_error
38
+ end
39
+
40
+ private :require
41
+ private :gem_original_require
42
+
43
+ end unless Kernel.private_method_defined?(:gem_original_require)
44
+
data/data/irbrc ADDED
@@ -0,0 +1,55 @@
1
+ # -*- Ruby -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+ # We use this as the default startup file for irb inside trepan
4
+ # Down the line we will have a way for folks to add/override this
5
+ # with their own file.
6
+ IRB.conf[:PROMPT_MODE] = :SIMPLE
7
+ IRB.conf[:PROMPT][:SIMPLE] =
8
+ {:PROMPT_C=>"trepan ?> ",
9
+ :PROMPT_I=>"trepan >> ",
10
+ :PROMPT_N=>"trepan >> ",
11
+ :PROMPT_S=>nil,
12
+ :RETURN=>"=> %s\n"}
13
+
14
+ # Using dbgr to issue a debugger statement inside irb:
15
+ # dbgr %w(info program)
16
+ # dbgr 'info program' # also works
17
+ # But...
18
+ # dbgr info program # wrong!
19
+ #
20
+ puts "You are in a trepan session. You should have access to program scope."
21
+ puts "'dbgr', 'step', 'n', 'q', 'cont' commands have been added."
22
+
23
+ if defined?($trepan) && $trepan
24
+ puts 'You should have access to debugger state via global variable $trepan'
25
+ end
26
+ if defined?($trepan_frame) && $trepan_frame
27
+ puts 'You should have access to the program frame via global variable $trepan_frame'
28
+ end
29
+ if defined?($trepan_cmdproc) && $trepan_cmdproc
30
+ puts 'You should have access to the command processor via global variable $trepan_cmdproc'
31
+ end
32
+
33
+ # Monkeypatch to save the current IRB statement to be run and make the instruction sequence
34
+ # "filename" unique. Possibly not needed.
35
+ class IRB::Context
36
+ def evaluate(line, line_no)
37
+ $trepan_irb_statements = line
38
+ @line_no = line_no
39
+ @eval_counter ||= 0
40
+ container =
41
+ if irb_path =~ /\((.+)\)/
42
+ # Note we originally had a colon below. This causes IRB to think
43
+ # tracebacks are IRB bugs since the regexp matching it uses here
44
+ # is now messed up. (irb:5): in ... vs (irb): in ...
45
+ "(#{$1}[#{@eval_counter}])"
46
+ else
47
+ irb_path
48
+ end
49
+ set_last_value(@workspace.evaluate(self, line, container, line_no))
50
+ # @workspace.evaluate("_ = IRB.conf[:MAIN_CONTEXT]._")
51
+ # @_ = @workspace.evaluate(line, irb_path, line_no)
52
+ @eval_counter += 1
53
+ end
54
+ end
55
+
data/data/prelude.rb ADDED
@@ -0,0 +1,38 @@
1
+
2
+ # Mutex
3
+
4
+ class Mutex
5
+ def synchronize
6
+ self.lock
7
+ begin
8
+ yield
9
+ ensure
10
+ self.unlock rescue nil
11
+ end
12
+ end
13
+ end
14
+
15
+ # Thread
16
+
17
+ class Thread
18
+ MUTEX_FOR_THREAD_EXCLUSIVE = Mutex.new
19
+ def self.exclusive
20
+ MUTEX_FOR_THREAD_EXCLUSIVE.synchronize{
21
+ yield
22
+ }
23
+ end
24
+ end
25
+
26
+ module Kernel
27
+ module_function
28
+ def require_relative(relative_feature)
29
+ c = caller.first
30
+ e = c.rindex(/:\d+:in /)
31
+ file = $`
32
+ if /\A\((.*)\)/ =~ file # eval, etc.
33
+ raise LoadError, "require_relative is called in #{$1}"
34
+ end
35
+ absolute_feature = File.expand_path(File.join(File.dirname(file), relative_feature))
36
+ require absolute_feature
37
+ end
38
+ end
@@ -0,0 +1,95 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # A base class for a debugger interface.
5
+
6
+ class Trepan
7
+
8
+ unless defined?(NotImplementedMessage)
9
+ NotImplementedMessage = 'This method must be overriden in a subclass'
10
+ end
11
+
12
+ # A debugger interface handles the communication or interaction with between
13
+ # the program and the outside portion which could be
14
+ # - a user,
15
+ # - a front-end that talks to a user, or
16
+ # - another interface in another process or computer
17
+ class Interface
18
+
19
+ attr_accessor :interactive, :input, :output
20
+
21
+ unless defined?(YES)
22
+ YES = %w(y yes oui si yep ja)
23
+ NO = %w(n no non nope nein)
24
+ YES_OR_NO = YES + NO
25
+ end
26
+
27
+ def initialize(inp=nil, out=nil, opts={})
28
+ @input = inp || STDIN
29
+ @interactive = false
30
+ @opts = opts
31
+ @output = out || STDOUT
32
+ end
33
+
34
+ # Closes all input and/or output.
35
+ def close
36
+ @input.close unless @input.closed?
37
+ @output.close unless @output.closed?
38
+ end
39
+
40
+ # Called when a dangerous action is about to be done to make sure
41
+ # it's okay. `prompt' is printed; user response is returned.
42
+ def confirm(prompt, default=false)
43
+ raise RuntimeError, Trepan::NotImplementedMessage
44
+ end
45
+
46
+ # Common routine for reporting debugger error messages.
47
+ def errmsg(str, prefix='** ')
48
+ if str.is_a?(Array)
49
+ str.each{|s| errmsg(s)}
50
+ else
51
+ str.split("\n").each do |s|
52
+ msg("%s%s" % [prefix, s])
53
+ end
54
+ end
55
+ end
56
+
57
+ def finalize(last_wishes=nil)
58
+ close
59
+ end
60
+
61
+ # Return true if interface is interactive.
62
+ def interactive?
63
+ # Default false and making subclasses figure out how to determine
64
+ # interactiveness.
65
+ false
66
+ end
67
+
68
+ # used to write to a debugger that is connected to this
69
+ # server; `str' written will have a newline added to it.
70
+ def msg(message)
71
+ if message.is_a?(Array)
72
+ message.each{|s| msg(s)}
73
+ else
74
+ message = message ? message.to_s + "\n" : ''
75
+ @output.write(message)
76
+ end
77
+ end
78
+
79
+ # used to write to a debugger that is connected to this
80
+ # server; `str' written will not have a newline added to it
81
+ def msg_nocr(msg)
82
+ @output.write(msg)
83
+ end
84
+
85
+ def read_command( prompt)
86
+ raise RuntimeError, Trepan::NotImplementedMessage
87
+ end
88
+
89
+ def readline(prompt='')
90
+ @output.flush
91
+ @output.write(prompt) if prompt and prompt.size > 0
92
+ @input.readline
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Module for reading debugger scripts
5
+
6
+ # Our local modules
7
+ require_relative 'base_intf'
8
+ require_relative '../io/input'
9
+ require_relative '../io/string_array'
10
+
11
+ # Interface when reading debugger scripts
12
+ class Trepan::ScriptInterface < Trepan::Interface
13
+
14
+ DEFAULT_OPTS = {
15
+ :abort_on_error => true,
16
+ :confirm_val => false,
17
+ :verbose => false
18
+ } unless defined?(DEFAULT_OPTS)
19
+
20
+ def initialize(script_name, out=nil, opts={})
21
+
22
+ @opts = DEFAULT_OPTS.merge(opts)
23
+
24
+ at_exit { finalize }
25
+ @script_name = script_name
26
+ @input_lineno = 0
27
+ @input = Trepan::UserInput.open(script_name,
28
+ :line_edit => false)
29
+ @buffer_output = []
30
+ unless opts[:verbose] or out
31
+ out = Trepan::StringArrayOutput.open(@buffer_output)
32
+ end
33
+ super(@input, out, @opts)
34
+ end
35
+
36
+ # Closes input only.
37
+ def close
38
+ @input.close
39
+ end
40
+
41
+ # Called when a dangerous action is about to be done, to make
42
+ # sure it's okay.
43
+ #
44
+ # Could look also look for interactive input and
45
+ # use that. For now, though we'll simplify.
46
+ def confirm(prompt, default)
47
+ @opts[:default_confirm]
48
+ end
49
+
50
+ # Common routine for reporting debugger error messages.
51
+ #
52
+ def errmsg(msg, prefix="*** ")
53
+ # self.verbose shows lines so we don't have to duplicate info
54
+ # here. Perhaps there should be a 'terse' mode to never show
55
+ # position info.
56
+ mess = if not @opts[:verbose]
57
+ location = ("%s:%s: Error in source command file" %
58
+ [@script_name, @input_lineno])
59
+ "%s%s:\n%s%s" % [prefix, location, prefix, msg]
60
+ else
61
+ "%s%s" % [prefix, msg]
62
+ end
63
+ msg(mess)
64
+ # FIXME: should we just set a flag and report eof? to be more
65
+ # consistent with File and IO?
66
+ raise IOError if @opts[:abort_on_error]
67
+ end
68
+
69
+ def interactive? ; false end
70
+
71
+ # Script interface to read a command. `prompt' is a parameter for
72
+ # compatibilty and is ignored.
73
+ def read_command(prompt='')
74
+ @input_lineno += 1
75
+ line = readline
76
+ if @opts[:verbose]
77
+ location = "%s line %s" % [@script_name, @input_lineno]
78
+ msg('+ %s: %s' % [location, line])
79
+ end
80
+ # Do something with history?
81
+ return line
82
+ end
83
+
84
+ # Script interface to read a line. `prompt' is a parameter for
85
+ # compatibilty and is ignored.
86
+ #
87
+ # Could decide make this look for interactive input?
88
+ def readline(prompt='')
89
+ begin
90
+ return input.readline().chomp
91
+ rescue EOFError
92
+ @eof = true
93
+ raise EOFError
94
+ end
95
+ end
96
+ end
97
+
98
+ # Demo
99
+ if __FILE__ == $0
100
+ intf = Trepan::ScriptInterface.new(__FILE__)
101
+ line = intf.readline()
102
+ print "Line read: ", line
103
+ end
data/interface/user.rb ADDED
@@ -0,0 +1,90 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Interface when communicating with the user in the same process as
5
+ # the debugged program.
6
+
7
+ # Our local modules
8
+
9
+ require_relative 'base_intf'
10
+ require_relative '../io/input'
11
+
12
+ # Moutput = import_relative('dbg_output', '..io', 'pydbgr')
13
+
14
+ # Interface when communicating with the user in the same
15
+ # process as the debugged program.
16
+ class Trepan::UserInterface < Trepan::Interface
17
+
18
+ FILE_HISTORY = '.trapan_hist' unless defined?(FILE_HISTORY)
19
+
20
+ def initialize(inp=nil, out=nil, opts={})
21
+ super(inp, out, opts)
22
+ @input = if inp.class.ancestors.member?(Trepan::InputBase)
23
+ inp
24
+ else
25
+ Trepan::UserInput.open(inp)
26
+ end
27
+ end
28
+
29
+ # Closes both input and output
30
+
31
+ # Called when a dangerous action is about to be done, to make
32
+ # sure it's okay. Expect a yes/no answer to `prompt' which is printed,
33
+ # suffixed with a question mark and the default value. The user
34
+ # response converted to a boolean is returned.
35
+ def confirm(prompt, default)
36
+ default_str = default ? 'Y/n' : 'N/y'
37
+ while true do
38
+ begin
39
+ response = readline('%s (%s) ' % [prompt, default_str])
40
+ rescue EOFError
41
+ return default
42
+ end
43
+ response = response.strip.downcase
44
+
45
+ # We don't catch "Yes, I'm sure" or "NO!", but I leave that
46
+ # as an exercise for the reader.
47
+ break if YES_OR_NO.member?(response)
48
+ msg "Please answer 'yes' or 'no'. Try again."
49
+ end
50
+ return YES.member?(response)
51
+ end
52
+
53
+ def finalize(last_wishes=nil)
54
+ # print exit annotation
55
+ # save history
56
+ super
57
+ end
58
+
59
+ def interactive? ; @input.interactive? end
60
+
61
+ def read_command(prompt='')
62
+ line = readline(prompt)
63
+ # FIXME: Do something with history?
64
+ return line
65
+ end
66
+ end
67
+
68
+ # Demo
69
+ if __FILE__ == $0
70
+ intf = Trepan::UserInterface.new
71
+ intf.errmsg("Houston, we have a problem here!")
72
+ if ARGV.size > 0
73
+ begin
74
+ line = intf.readline("Type something: ")
75
+ rescue EOFError
76
+ puts "No input, got EOF"
77
+ else
78
+ puts "You typed: #{line}"
79
+ end
80
+ puts "EOF is now: %s" % intf.input.eof?.inspect
81
+ unless intf.input.eof?
82
+ line = intf.confirm("Are you sure", false)
83
+ puts "You typed: #{line}"
84
+ puts "EOF is now: %s" % intf.input.eof?.inspect
85
+ line = intf.confirm("Are you not sure", true)
86
+ puts "You typed: #{line}"
87
+ puts "EOF is now: %s" % intf.input.eof?.inspect
88
+ end
89
+ end
90
+ end
data/io/base_io.rb ADDED
@@ -0,0 +1,92 @@
1
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
2
+ # classes to support communication to and from the debugger. This
3
+ # communcation might be to/from another process or another computer.
4
+ # And reading may be from a debugger command script.
5
+ #
6
+ # For example, we'd like to support Sockets, and serial lines and file
7
+ # reading, as well a readline-type input. Encryption and Authentication
8
+ # methods might decorate some of the communication channels.
9
+ #
10
+ # Some ideas originiated as part of Matt Fleming's 2006 Google Summer of
11
+ # Code project.
12
+
13
+ class Trepan
14
+
15
+ NotImplementedMessage = 'This method must be overriden in a subclass' unless
16
+ defined?(NotImplementedMessage)
17
+
18
+ class InputBase
19
+ attr_reader :input
20
+ attr_reader :line_edit
21
+
22
+ DEFAULT_OPTS = {
23
+ :line_edit => false,
24
+ } unless defined?(DEFAULT_OPTS)
25
+
26
+ def initialize(inp, opts={})
27
+ @opts = DEFAULT_OPTS.merge(opts)
28
+ @input = inp
29
+ @line_edit = opts[:line_edit]
30
+ end
31
+
32
+ def close
33
+ @input.close unless @input.closed?
34
+ end
35
+
36
+ def eof?
37
+ begin
38
+ @input.eof?
39
+ rescue IOError
40
+ true
41
+ end
42
+ end
43
+
44
+ # Read a line of input. EOFError will be raised on EOF.
45
+ #
46
+ # Note that we don't support prompting first. Instead, arrange
47
+ # to call Trepan::Output.write() first with the prompt. If
48
+ # `use_raw' is set raw_input() will be used in that is supported
49
+ # by the specific input input. If this option is left None as is
50
+ # normally expected the value from the class initialization is
51
+ # used.
52
+ def readline
53
+ @input.readline
54
+ end
55
+ end
56
+
57
+ # This is an abstract class that specifies debugger output.
58
+ class OutputBase
59
+ attr_accessor :flush_after_write
60
+ attr_reader :output
61
+ def initialize(out, opts={})
62
+ @output = out
63
+ @flush_after_write = false
64
+ end
65
+
66
+ def close
67
+ @output.close if @output
68
+ end
69
+
70
+ def eof?
71
+ @input.eof?
72
+ end
73
+
74
+ def flush
75
+ @output.flush
76
+ end
77
+
78
+ # Use this to set where to write to. output can be a
79
+ # file object or a string. This code raises IOError on error.
80
+ def write(*args)
81
+ @output.print(*args)
82
+ end
83
+
84
+ # used to write to a debugger that is connected to this
85
+ # `str' written will have a newline added to it
86
+ #
87
+ def writeline( msg)
88
+ @output.write("%s\n" % msg)
89
+ end
90
+ end
91
+ end
92
+
data/io/input.rb ADDED
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (C) 2010 Rocky Bernstein <rockyb@rubyforge.net>
3
+
4
+ # Debugger user/command-oriented input possibly attached to IO-style
5
+ # input or GNU Readline.
6
+ #
7
+
8
+ require_relative 'base_io'
9
+
10
+ class Trepan
11
+
12
+ # Debugger user/command-oriented input possibly attached to IO-style
13
+ # input or GNU Readline.
14
+ class UserInput < Trepan::InputBase
15
+
16
+ def initialize(inp, opts={})
17
+ @opts = DEFAULT_OPTS.merge(opts)
18
+ @input = inp || STDIN
19
+ @eof = false
20
+ end
21
+
22
+ def closed?; @input.closed? end
23
+ def eof?; @eof end
24
+
25
+ def interactive?
26
+ @input.respond_to?(:isatty) && @input.isatty
27
+ end
28
+
29
+ # Read a line of input. EOFError will be raised on EOF.
30
+ #
31
+ # Note that we don't support prompting first. Instead, arrange
32
+ # to call Trepan::Output.write() first with the prompt.
33
+ def readline
34
+ # FIXME we don't do command completion.
35
+ raise EOFError if eof?
36
+ begin
37
+ line = @opts[:line_edit] ? Readline.readline : @input.gets
38
+ @eof = !line
39
+ rescue
40
+ @eof = true
41
+ end
42
+ raise EOFError if eof?
43
+ return line
44
+ end
45
+
46
+ class << self
47
+ # Use this to set where to read from.
48
+ #
49
+ # Set opts[:line_edit] if you want this input to interact with
50
+ # GNU-like readline library. By default, we will assume to try
51
+ # using readline.
52
+ def open(inp=nil, opts={})
53
+ inp ||= STDIN
54
+ inp = File.new(inp, 'r') if inp.is_a?(String)
55
+ opts[:line_edit] = false unless
56
+ inp.respond_to?(:isatty) && inp.isatty && Trepan::GNU_readline?
57
+ self.new(inp, opts)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ def Trepan::GNU_readline?
64
+ begin
65
+ require 'readline'
66
+ return true
67
+ rescue LoadError
68
+ return false
69
+ end
70
+ end
71
+
72
+ # Demo
73
+ if __FILE__ == $0
74
+ puts 'Have GNU is: %s' % Trepan::GNU_readline?
75
+ inp = Trepan::UserInput.open(__FILE__, :line_edit => false)
76
+ line = inp.readline
77
+ puts line
78
+ inp.close
79
+ filename = 'input.py'
80
+ begin
81
+ Trepan::UserInput.open(filename)
82
+ rescue
83
+ puts "Can't open #{filename} for reading: #{$!}"
84
+ end
85
+ inp = Trepan::UserInput.open(__FILE__, :line_edit => false)
86
+ while true
87
+ begin
88
+ inp.readline
89
+ rescue EOFError
90
+ break
91
+ end
92
+ end
93
+ begin
94
+ inp.readline
95
+ rescue EOFError
96
+ puts 'EOF handled correctly'
97
+ end
98
+
99
+ if ARGV.size > 0
100
+ inp = Trepan::UserInput.open
101
+ begin
102
+ print "Type some characters: "
103
+ line = inp.readline()
104
+ puts "You typed: %s" % line
105
+ rescue EOFError
106
+ puts 'Got EOF'
107
+ end
108
+ end
109
+ end
110
+
111
+