ruby-debug 0.9.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGES +41 -0
- data/ChangeLog +0 -0
- data/README +27 -13
- data/Rakefile +220 -0
- data/bin/rdebug +116 -42
- data/cli/ruby-debug.rb +33 -3
- data/cli/ruby-debug/command.rb +49 -12
- data/cli/ruby-debug/commands/breakpoints.rb +47 -64
- data/cli/ruby-debug/commands/control.rb +41 -13
- data/cli/ruby-debug/commands/display.rb +35 -18
- data/cli/ruby-debug/commands/enable.rb +159 -0
- data/cli/ruby-debug/commands/eval.rb +78 -4
- data/cli/ruby-debug/commands/frame.rb +67 -42
- data/cli/ruby-debug/commands/help.rb +21 -17
- data/cli/ruby-debug/commands/info.rb +210 -0
- data/cli/ruby-debug/commands/irb.rb +9 -1
- data/cli/ruby-debug/commands/list.rb +11 -8
- data/cli/ruby-debug/commands/method.rb +12 -23
- data/cli/ruby-debug/commands/script.rb +14 -9
- data/cli/ruby-debug/commands/settings.rb +174 -39
- data/cli/ruby-debug/commands/show.rb +193 -0
- data/cli/ruby-debug/commands/stepping.rb +15 -10
- data/cli/ruby-debug/commands/threads.rb +55 -56
- data/cli/ruby-debug/commands/variables.rb +27 -27
- data/cli/ruby-debug/helper.rb +134 -0
- data/cli/ruby-debug/interface.rb +46 -15
- data/cli/ruby-debug/processor.rb +156 -25
- data/doc/rdebug.1 +236 -0
- data/runner.sh +7 -0
- data/test/breakpoints.cmd +43 -0
- data/test/breakpoints.right +94 -0
- data/test/display.cmd +18 -0
- data/test/display.right +37 -0
- data/test/frame.cmd +21 -0
- data/test/frame.right +45 -0
- data/test/gcd.rb +18 -0
- data/test/help.cmd +12 -0
- data/test/help.right +4 -0
- data/test/helper.rb +87 -0
- data/test/info-var-bug.rb +45 -0
- data/test/info-var.cmd +23 -0
- data/test/info-var.right +47 -0
- data/test/info.cmd +12 -0
- data/test/info.right +35 -0
- data/test/quit.cmd +9 -0
- data/test/quit.right +22 -0
- data/test/setshow.cmd +44 -0
- data/test/setshow.right +73 -0
- data/test/stepping.cmd +17 -0
- data/test/stepping.right +40 -0
- data/test/tdebug.rb +196 -0
- data/test/test-breakpoints.rb +28 -0
- data/test/test-columnize.rb +46 -0
- data/test/test-display.rb +26 -0
- data/test/test-frame.rb +27 -0
- data/test/test-help.rb +44 -0
- data/test/test-info-var.rb +33 -0
- data/test/test-info.rb +28 -0
- data/test/test-quit.rb +28 -0
- data/test/test-ruby-debug-base.rb +76 -0
- data/test/test-setshow.rb +24 -0
- data/test/test-stepping.rb +26 -0
- metadata +63 -22
data/cli/ruby-debug.rb
CHANGED
@@ -9,11 +9,25 @@ module Debugger
|
|
9
9
|
self.handler = CommandProcessor.new
|
10
10
|
|
11
11
|
# the port number used for remote debugging
|
12
|
-
PORT = 8989
|
12
|
+
PORT = 8989 unless defined?(PORT)
|
13
13
|
|
14
|
+
# What file is used for debugger startup commands.
|
15
|
+
unless defined?(INITFILE)
|
16
|
+
if RUBY_PLATFORM =~ /mswin/
|
17
|
+
# Of course MS Windows has to be different
|
18
|
+
INITFILE = 'rdebug.ini'
|
19
|
+
HOME_DIR = (ENV['HOME'] ||
|
20
|
+
ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
|
21
|
+
else
|
22
|
+
INITFILE = '.rdebugrc'
|
23
|
+
HOME_DIR = ENV['HOME'].to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
14
27
|
class << self
|
15
28
|
# in remote mode, wait for the remote connection
|
16
29
|
attr_accessor :wait_connection
|
30
|
+
attr_accessor :annotate
|
17
31
|
|
18
32
|
attr_reader :thread, :control_thread
|
19
33
|
|
@@ -105,13 +119,29 @@ module Debugger
|
|
105
119
|
socket.close
|
106
120
|
end
|
107
121
|
|
122
|
+
# Runs normal debugger initialization scripts
|
123
|
+
# Reads and executes the commands from init file (if any) in the
|
124
|
+
# current working directory. This is only done if the current
|
125
|
+
# directory is different from your home directory. Thus, you can
|
126
|
+
# have more than one init file, one generic in your home directory,
|
127
|
+
# and another, specific to the program you are debugging, in the
|
128
|
+
# directory where you invoke ruby-debug.
|
129
|
+
def run_init_script(out = handler.interface)
|
130
|
+
cwd_script_file = File.expand_path(File.join(".", INITFILE))
|
131
|
+
run_script(cwd_script_file, out) if File.exists?(cwd_script_file)
|
132
|
+
|
133
|
+
home_script_file = File.expand_path(File.join(HOME_DIR, INITFILE))
|
134
|
+
run_script(home_script_file, out) if File.exists?(home_script_file) and
|
135
|
+
cwd_script_file != home_script_file
|
136
|
+
end
|
137
|
+
|
108
138
|
#
|
109
139
|
# Runs a script file
|
110
140
|
#
|
111
141
|
def run_script(file, out = handler.interface)
|
112
|
-
interface = ScriptInterface.new(file, out)
|
142
|
+
interface = ScriptInterface.new(File.expand_path(file), out)
|
113
143
|
processor = ControlCommandProcessor.new(interface)
|
114
144
|
processor.process_commands
|
115
145
|
end
|
116
146
|
end
|
117
|
-
end
|
147
|
+
end
|
data/cli/ruby-debug/command.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
require 'ruby-debug/helper'
|
2
|
+
|
1
3
|
module Debugger
|
4
|
+
|
2
5
|
class Command # :nodoc:
|
3
6
|
class << self
|
4
7
|
def commands
|
@@ -8,10 +11,10 @@ module Debugger
|
|
8
11
|
DEF_OPTIONS = {
|
9
12
|
:event => true,
|
10
13
|
:control => false,
|
11
|
-
:always_run =>
|
14
|
+
:always_run => 0,
|
12
15
|
:unknown => false,
|
13
16
|
:need_context => false,
|
14
|
-
}
|
17
|
+
} unless defined?(DEF_OPTIONS)
|
15
18
|
|
16
19
|
def inherited(klass)
|
17
20
|
DEF_OPTIONS.each do |o, v|
|
@@ -25,6 +28,9 @@ module Debugger
|
|
25
28
|
Dir[File.join(dir, 'commands', '*')].each do |file|
|
26
29
|
require file if file =~ /\.rb$/
|
27
30
|
end
|
31
|
+
Debugger.constants.grep(/Functions$/).map { |name| Debugger.const_get(name) }.each do |mod|
|
32
|
+
include mod
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
def method_missing(meth, *args, &block)
|
@@ -49,16 +55,32 @@ module Debugger
|
|
49
55
|
private :settings_map
|
50
56
|
|
51
57
|
def settings
|
52
|
-
unless @settings
|
58
|
+
unless true and defined? @settings and @settings
|
53
59
|
@settings = Object.new
|
54
60
|
map = settings_map
|
55
|
-
class << @settings; self end
|
56
|
-
|
57
|
-
|
61
|
+
c = class << @settings; self end
|
62
|
+
if c.respond_to?(:funcall)
|
63
|
+
c.funcall(:define_method, :[]) do |name|
|
64
|
+
raise "No such setting #{name}" unless map.has_key?(name)
|
65
|
+
map[name][:getter].call
|
66
|
+
end
|
67
|
+
else
|
68
|
+
c.send(:define_method, :[]) do |name|
|
69
|
+
raise "No such setting #{name}" unless map.has_key?(name)
|
70
|
+
map[name][:getter].call
|
71
|
+
end
|
58
72
|
end
|
59
|
-
class << @settings; self end
|
60
|
-
|
61
|
-
|
73
|
+
c = class << @settings; self end
|
74
|
+
if c.respond_to?(:funcall)
|
75
|
+
c.funcall(:define_method, :[]=) do |name, value|
|
76
|
+
raise "No such setting #{name}" unless map.has_key?(name)
|
77
|
+
map[name][:setter].call(value)
|
78
|
+
end
|
79
|
+
else
|
80
|
+
c.send(:define_method, :[]=) do |name, value|
|
81
|
+
raise "No such setting #{name}" unless map.has_key?(name)
|
82
|
+
map[name][:setter].call(value)
|
83
|
+
end
|
62
84
|
end
|
63
85
|
end
|
64
86
|
@settings
|
@@ -82,10 +104,25 @@ module Debugger
|
|
82
104
|
end
|
83
105
|
end
|
84
106
|
|
85
|
-
register_setting_var(:
|
86
|
-
register_setting_var(:
|
87
|
-
register_setting_var(:
|
107
|
+
register_setting_var(:basename, false) # use basename in showing files?
|
108
|
+
register_setting_var(:callstyle, :last)
|
109
|
+
register_setting_var(:debuggertesting, false)
|
88
110
|
register_setting_var(:force_stepping, false)
|
111
|
+
register_setting_var(:full_path, true)
|
112
|
+
register_setting_var(:listsize, 10) # number of lines in list command
|
113
|
+
register_setting_var(:stack_trace_on_error, false)
|
114
|
+
register_setting_var(:tracing_plus, false) # different linetrace lines?
|
115
|
+
|
116
|
+
# width of line output. Use COLUMNS value if it exists and is
|
117
|
+
# not too rediculously large.
|
118
|
+
width = ENV['COLUMNS'].to_i
|
119
|
+
width = 80 unless width > 10
|
120
|
+
register_setting_var(:width, width)
|
121
|
+
|
122
|
+
if not defined? Debugger::ARGV
|
123
|
+
Debugger::ARGV = ARGV.clone
|
124
|
+
end
|
125
|
+
register_setting_var(:argv, Debugger::ARGV)
|
89
126
|
|
90
127
|
def initialize(state)
|
91
128
|
@state = state
|
@@ -5,11 +5,11 @@ module Debugger
|
|
5
5
|
def regexp
|
6
6
|
/ ^\s*
|
7
7
|
b(?:reak)?
|
8
|
-
\s+
|
8
|
+
(?: \s+
|
9
9
|
(?:
|
10
10
|
(\d+) |
|
11
11
|
(.+?)[:.#]([^.:\s]+)
|
12
|
-
)
|
12
|
+
))?
|
13
13
|
(?:\s+
|
14
14
|
if\s+(.+)
|
15
15
|
)?
|
@@ -19,35 +19,50 @@ module Debugger
|
|
19
19
|
|
20
20
|
def execute
|
21
21
|
if @match[1]
|
22
|
-
|
22
|
+
line, _, _, expr = @match.captures
|
23
23
|
else
|
24
|
-
_, file,
|
24
|
+
_, file, line, expr = @match.captures
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
|
+
full_file = nil
|
27
28
|
if file.nil?
|
29
|
+
full_file = @state.file
|
28
30
|
file = File.basename(@state.file)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
if line.nil?
|
32
|
+
# Set breakpoint at current line
|
33
|
+
line = @state.line.to_s
|
34
|
+
end
|
35
|
+
elsif line !~ /^\d+$/
|
36
|
+
# See if "line" is a method/function name
|
37
|
+
klass = debug_silent_eval(file)
|
38
|
+
if klass && klass.kind_of?(Module)
|
39
|
+
class_name = klass.name if klass
|
37
40
|
else
|
38
|
-
|
39
|
-
|
41
|
+
print "Unknown class #{file}.\n"
|
42
|
+
throw :debug_error
|
40
43
|
end
|
44
|
+
else
|
45
|
+
file = File.expand_path(file) if file.index(File::SEPARATOR) || \
|
46
|
+
File::ALT_SEPARATOR && file.index(File::ALT_SEPARATOR)
|
47
|
+
full_file = file
|
41
48
|
end
|
42
49
|
|
43
|
-
if
|
44
|
-
|
50
|
+
if line =~ /^\d+$/
|
51
|
+
line = line.to_i
|
52
|
+
lines = Debugger.source_for(full_file)
|
53
|
+
if not lines
|
54
|
+
print "No source file named %s\n", file
|
55
|
+
elsif lines.size < line
|
56
|
+
print "No line %d in file \"%s\"\n", line, file
|
57
|
+
else
|
58
|
+
b = Debugger.add_breakpoint file, line, expr
|
59
|
+
print "Breakpoint %d file %s, line %s\n", b.id, file, line.to_s
|
60
|
+
end
|
45
61
|
else
|
46
|
-
|
62
|
+
method = line.intern.id2name
|
63
|
+
b = Debugger.add_breakpoint class_name, method, expr
|
64
|
+
print "Breakpoint %d at %s::%s\n", b.id, class_name, method.to_s
|
47
65
|
end
|
48
|
-
|
49
|
-
b = Debugger.add_breakpoint file, pos, expr
|
50
|
-
print "Set breakpoint %d at %s:%s\n", b.id, file, pos.to_s
|
51
66
|
end
|
52
67
|
|
53
68
|
class << self
|
@@ -65,58 +80,26 @@ module Debugger
|
|
65
80
|
end
|
66
81
|
end
|
67
82
|
|
68
|
-
class BreakpointsCommand < Command # :nodoc:
|
69
|
-
self.control = true
|
70
|
-
|
71
|
-
def regexp
|
72
|
-
/^\s*b(?:reak)?$/
|
73
|
-
end
|
74
|
-
|
75
|
-
def execute
|
76
|
-
unless Debugger.breakpoints.empty?
|
77
|
-
print "Breakpoints:\n"
|
78
|
-
Debugger.breakpoints.sort_by{|b| b.id }.each do |b|
|
79
|
-
if b.expr.nil?
|
80
|
-
print " %d %s:%s\n", b.id, b.source, b.pos
|
81
|
-
else
|
82
|
-
print " %d %s:%s if %s\n", b.id, b.source, b.pos, b.expr
|
83
|
-
end
|
84
|
-
end
|
85
|
-
else
|
86
|
-
print "No breakpoints\n"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
class << self
|
91
|
-
def help_command
|
92
|
-
'break'
|
93
|
-
end
|
94
|
-
|
95
|
-
def help(cmd)
|
96
|
-
%{
|
97
|
-
b[reak]\tlist breakpoints
|
98
|
-
}
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
83
|
class DeleteBreakpointCommand < Command # :nodoc:
|
104
84
|
self.control = true
|
105
85
|
|
106
86
|
def regexp
|
107
|
-
/^\s*del(?:ete)?(?:\s+(
|
87
|
+
/^\s*del(?:ete)?(?:\s+(.*))?$/
|
108
88
|
end
|
109
89
|
|
110
90
|
def execute
|
111
|
-
|
112
|
-
unless
|
113
|
-
if confirm("
|
91
|
+
brkpts = @match[1]
|
92
|
+
unless brkpts
|
93
|
+
if confirm("Delete all breakpoints? (y or n) ")
|
114
94
|
Debugger.breakpoints.clear
|
115
95
|
end
|
116
96
|
else
|
117
|
-
|
118
|
-
|
119
|
-
|
97
|
+
brkpts.split(/[ \t]+/).each do |pos|
|
98
|
+
pos = get_int(pos, "Delete", 1)
|
99
|
+
return unless pos
|
100
|
+
unless Debugger.remove_breakpoint(pos)
|
101
|
+
print "No breakpoint number %d\n", pos
|
102
|
+
end
|
120
103
|
end
|
121
104
|
end
|
122
105
|
end
|
@@ -128,7 +111,7 @@ module Debugger
|
|
128
111
|
|
129
112
|
def help(cmd)
|
130
113
|
%{
|
131
|
-
del[ete][ nnn]\tdelete some or all breakpoints
|
114
|
+
del[ete][ nnn...]\tdelete some or all breakpoints
|
132
115
|
}
|
133
116
|
end
|
134
117
|
end
|
@@ -3,11 +3,11 @@ module Debugger
|
|
3
3
|
self.control = true
|
4
4
|
|
5
5
|
def regexp
|
6
|
-
/^\s*(?:q(?:uit)?|exit)\s*$/
|
6
|
+
/^\s*(?:q(?:uit)?|exit)\s*(\s+unconditionally)?\s*$/
|
7
7
|
end
|
8
8
|
|
9
9
|
def execute
|
10
|
-
if confirm("Really quit? (y/n) ")
|
10
|
+
if @match[1] or confirm("Really quit? (y/n) ")
|
11
11
|
Debugger.save_history if Debugger.respond_to? :save_history
|
12
12
|
exit! # exit -> exit!: No graceful way to stop threads...
|
13
13
|
end
|
@@ -20,8 +20,11 @@ module Debugger
|
|
20
20
|
|
21
21
|
def help(cmd)
|
22
22
|
%{
|
23
|
-
q[uit]\texit from debugger
|
23
|
+
q[uit] [unconditionally]\texit from debugger.
|
24
24
|
exit\talias to quit
|
25
|
+
|
26
|
+
Normally we prompt before exiting. However if the parameter
|
27
|
+
"unconditionally" is given, we stop without asking further questions.
|
25
28
|
}
|
26
29
|
end
|
27
30
|
end
|
@@ -32,25 +35,50 @@ module Debugger
|
|
32
35
|
|
33
36
|
def regexp
|
34
37
|
/ ^\s*
|
35
|
-
(restart|R)
|
36
|
-
(
|
38
|
+
(?:restart|R)
|
39
|
+
(?:\s+ (\S?.*\S))? \s*
|
37
40
|
$
|
38
|
-
/
|
41
|
+
/ix
|
39
42
|
end
|
40
43
|
|
41
44
|
def execute
|
42
|
-
if not defined? Debugger::RDEBUG_SCRIPT
|
43
|
-
|
45
|
+
if not defined? Debugger::RDEBUG_SCRIPT
|
46
|
+
# FIXME? Should ask for confirmation?
|
47
|
+
print "Debugger was not called from the outset...\n"
|
48
|
+
rdebug_script = ''
|
49
|
+
else
|
50
|
+
rdebug_script = Debugger::RDEBUG_SCRIPT + " "
|
51
|
+
end
|
52
|
+
prog_script = Debugger::PROG_SCRIPT
|
53
|
+
begin
|
54
|
+
Dir.chdir(Debugger::INITIAL_DIR)
|
55
|
+
rescue
|
56
|
+
print "Failed to change initial directory #{Debugger::INITIAL_DIR}"
|
57
|
+
end
|
58
|
+
if not File.exists?(prog_script)
|
59
|
+
print "Ruby program #{prog_script} doesn't exist\n"
|
44
60
|
return
|
45
61
|
end
|
46
|
-
if
|
47
|
-
|
62
|
+
if not File.executable?(prog_script) and rdebug_script == ''
|
63
|
+
print "Ruby program #{prog_script} doesn't seem to be executable...\n"
|
64
|
+
print "We'll add a call to Ruby.\n"
|
65
|
+
ruby = begin defined?(Gem) ? Gem.ruby : "ruby" rescue "ruby" end
|
66
|
+
rdebug_script = "#{ruby} -I#{$:.join(' -I')} #{prog_script}"
|
67
|
+
end
|
68
|
+
if @match[1]
|
69
|
+
argv = [prog_script] + @match[1].split(/[ \t]+/)
|
48
70
|
else
|
49
|
-
|
71
|
+
if not defined? Command.settings[:argv]
|
72
|
+
print "Arguments have not been set. Use 'set args' to set them.\n"
|
73
|
+
return
|
74
|
+
else
|
75
|
+
argv = Command.settings[:argv]
|
76
|
+
end
|
50
77
|
end
|
78
|
+
args = argv.join(" ")
|
51
79
|
|
52
80
|
# An execv would be preferable to the "exec" below.
|
53
|
-
cmd =
|
81
|
+
cmd = rdebug_script + args
|
54
82
|
print "Re exec'ing:\n\t#{cmd}\n"
|
55
83
|
exec cmd
|
56
84
|
rescue Errno::EOPNOTSUPP
|
@@ -100,4 +128,4 @@ module Debugger
|
|
100
128
|
end
|
101
129
|
end
|
102
130
|
end
|
103
|
-
end
|
131
|
+
end
|
@@ -3,11 +3,24 @@ module Debugger
|
|
3
3
|
def display_expression(exp)
|
4
4
|
print "%s = %s\n", exp, debug_silent_eval(exp).to_s
|
5
5
|
end
|
6
|
+
|
7
|
+
def active_display_expressions?
|
8
|
+
@state.display.select{|d| d[0]}.size > 0
|
9
|
+
end
|
10
|
+
|
11
|
+
def print_display_expressions
|
12
|
+
n = 1
|
13
|
+
for d in @state.display
|
14
|
+
if d[0]
|
15
|
+
print "%d: ", n
|
16
|
+
display_expression(d[1])
|
17
|
+
end
|
18
|
+
n += 1
|
19
|
+
end
|
20
|
+
end
|
6
21
|
end
|
7
22
|
|
8
23
|
class AddDisplayCommand < Command # :nodoc:
|
9
|
-
include DisplayFunctions
|
10
|
-
|
11
24
|
def regexp
|
12
25
|
/^\s*disp(?:lay)?\s+(.+)$/
|
13
26
|
end
|
@@ -33,22 +46,21 @@ module Debugger
|
|
33
46
|
end
|
34
47
|
|
35
48
|
class DisplayCommand < Command # :nodoc:
|
36
|
-
self.always_run
|
37
|
-
|
49
|
+
def self.always_run
|
50
|
+
Debugger.annotate = 0 unless Debugger.annotate
|
51
|
+
if Debugger.annotate > 1
|
52
|
+
0
|
53
|
+
else
|
54
|
+
2
|
55
|
+
end
|
56
|
+
end
|
38
57
|
|
39
58
|
def regexp
|
40
59
|
/^\s*disp(?:lay)?$/
|
41
60
|
end
|
42
61
|
|
43
62
|
def execute
|
44
|
-
|
45
|
-
for d in @state.display
|
46
|
-
if d[0]
|
47
|
-
print "%d: ", n
|
48
|
-
display_expression(d[1])
|
49
|
-
end
|
50
|
-
n += 1
|
51
|
-
end
|
63
|
+
print_display_expressions
|
52
64
|
end
|
53
65
|
|
54
66
|
class << self
|
@@ -65,10 +77,9 @@ module Debugger
|
|
65
77
|
end
|
66
78
|
|
67
79
|
class DeleteDisplayCommand < Command # :nodoc:
|
68
|
-
include DisplayFunctions
|
69
80
|
|
70
81
|
def regexp
|
71
|
-
/^\s*undisp(?:lay)?
|
82
|
+
/^\s* undisp(?:lay)? \s* (?:(\S+))?$/x
|
72
83
|
end
|
73
84
|
|
74
85
|
def execute
|
@@ -79,9 +90,10 @@ module Debugger
|
|
79
90
|
end
|
80
91
|
end
|
81
92
|
else
|
82
|
-
pos = pos
|
93
|
+
pos = get_int(pos, "Undisplay")
|
94
|
+
return unless pos
|
83
95
|
if @state.display[pos-1]
|
84
|
-
@state.display[pos-1][0] =
|
96
|
+
@state.display[pos-1][0] = nil
|
85
97
|
else
|
86
98
|
print "Display expression %d is not defined\n", pos
|
87
99
|
end
|
@@ -95,9 +107,14 @@ module Debugger
|
|
95
107
|
|
96
108
|
def help(cmd)
|
97
109
|
%{
|
98
|
-
undisp[lay][ nnn]
|
110
|
+
undisp[lay][ nnn]
|
111
|
+
Cancel some expressions to be displayed when program stops.
|
112
|
+
Arguments are the code numbers of the expressions to stop displaying.
|
113
|
+
No argument means cancel all automatic-display expressions.
|
114
|
+
"delete display" has the same effect as this command.
|
115
|
+
Do "info display" to see current list of code numbers.
|
99
116
|
}
|
100
117
|
end
|
101
118
|
end
|
102
119
|
end
|
103
|
-
end
|
120
|
+
end
|