scriptty 0.5.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitattributes +1 -0
- data/.gitignore +3 -0
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/README.rdoc +31 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/bin/scriptty-capture +5 -0
- data/bin/scriptty-dump-screens +4 -0
- data/bin/scriptty-replay +5 -0
- data/bin/scriptty-term-test +4 -0
- data/bin/scriptty-transcript-parse +4 -0
- data/examples/captures/xterm-overlong-line-prompt.bin +9 -0
- data/examples/captures/xterm-vim-session.bin +262 -0
- data/examples/demo-capture.rb +19 -0
- data/examples/telnet-nego.rb +55 -0
- data/lib/scriptty/apps/capture_app/console.rb +104 -0
- data/lib/scriptty/apps/capture_app/password_prompt.rb +65 -0
- data/lib/scriptty/apps/capture_app.rb +213 -0
- data/lib/scriptty/apps/dump_screens_app.rb +166 -0
- data/lib/scriptty/apps/replay_app.rb +229 -0
- data/lib/scriptty/apps/term_test_app.rb +124 -0
- data/lib/scriptty/apps/transcript_parse_app.rb +143 -0
- data/lib/scriptty/cursor.rb +39 -0
- data/lib/scriptty/exception.rb +38 -0
- data/lib/scriptty/expect.rb +392 -0
- data/lib/scriptty/multiline_buffer.rb +192 -0
- data/lib/scriptty/net/event_loop.rb +610 -0
- data/lib/scriptty/screen_pattern/generator.rb +398 -0
- data/lib/scriptty/screen_pattern/parser.rb +558 -0
- data/lib/scriptty/screen_pattern.rb +104 -0
- data/lib/scriptty/term/dg410/dg410-client-escapes.txt +37 -0
- data/lib/scriptty/term/dg410/dg410-escapes.txt +82 -0
- data/lib/scriptty/term/dg410/parser.rb +162 -0
- data/lib/scriptty/term/dg410.rb +489 -0
- data/lib/scriptty/term/xterm/xterm-escapes.txt +73 -0
- data/lib/scriptty/term/xterm.rb +661 -0
- data/lib/scriptty/term.rb +40 -0
- data/lib/scriptty/util/fsm/definition_parser.rb +111 -0
- data/lib/scriptty/util/fsm/scriptty_fsm_definition.treetop +189 -0
- data/lib/scriptty/util/fsm.rb +177 -0
- data/lib/scriptty/util/transcript/reader.rb +96 -0
- data/lib/scriptty/util/transcript/writer.rb +111 -0
- data/test/apps/capture_app_test.rb +123 -0
- data/test/apps/transcript_parse_app_test.rb +118 -0
- data/test/cursor_test.rb +51 -0
- data/test/fsm_definition_parser_test.rb +220 -0
- data/test/fsm_test.rb +322 -0
- data/test/multiline_buffer_test.rb +275 -0
- data/test/net/event_loop_test.rb +402 -0
- data/test/screen_pattern/generator_test.rb +408 -0
- data/test/screen_pattern/parser_test/explicit_cursor_pattern.txt +14 -0
- data/test/screen_pattern/parser_test/explicit_fields.txt +22 -0
- data/test/screen_pattern/parser_test/multiple_patterns.txt +42 -0
- data/test/screen_pattern/parser_test/simple_pattern.txt +14 -0
- data/test/screen_pattern/parser_test/truncated_heredoc.txt +12 -0
- data/test/screen_pattern/parser_test/utf16bebom_pattern.bin +0 -0
- data/test/screen_pattern/parser_test/utf16lebom_pattern.bin +0 -0
- data/test/screen_pattern/parser_test/utf8_pattern.bin +14 -0
- data/test/screen_pattern/parser_test/utf8_unix_pattern.bin +14 -0
- data/test/screen_pattern/parser_test/utf8bom_pattern.bin +14 -0
- data/test/screen_pattern/parser_test.rb +266 -0
- data/test/term/dg410/parser_test.rb +139 -0
- data/test/term/xterm_test.rb +327 -0
- data/test/test_helper.rb +3 -0
- data/test/util/transcript/reader_test.rb +131 -0
- data/test/util/transcript/writer_test.rb +126 -0
- data/test.watchr +29 -0
- metadata +175 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
# Terminal escapes for dg410
|
2
|
+
#'\001' => t_print_form
|
3
|
+
#'\002' => t_stx
|
4
|
+
'\003' => t_blink_enable
|
5
|
+
'\004' => t_blink_disable
|
6
|
+
#'\005' => t_read_window_address
|
7
|
+
'\006' => t_proprietary_ack
|
8
|
+
'\007' => t_bell
|
9
|
+
'\010' => t_window_home
|
10
|
+
#'\011' => t_tab
|
11
|
+
'\012' => t_new_line
|
12
|
+
'\013' => t_erase_end_of_line
|
13
|
+
'\014' => t_erase_window
|
14
|
+
'\015' => t_carriage_return
|
15
|
+
'\016' => t_blink_on
|
16
|
+
'\017' => t_blink_off
|
17
|
+
'\020' => {
|
18
|
+
* => {
|
19
|
+
* => t_write_window_address
|
20
|
+
}
|
21
|
+
}
|
22
|
+
'\021' => t_print_window
|
23
|
+
'\022' => t_roll_enable
|
24
|
+
'\023' => t_roll_disable
|
25
|
+
'\024' => t_underscore_on
|
26
|
+
'\025' => t_underscore_off
|
27
|
+
#'\026' => t_syn # seems to always be followed by some data, then \002 # XXX TODO
|
28
|
+
'\027' => t_cursor_up
|
29
|
+
'\030' => t_cursor_right
|
30
|
+
'\031' => t_cursor_left
|
31
|
+
'\032' => t_cursor_down
|
32
|
+
'\033' => {
|
33
|
+
# '\x20' => {
|
34
|
+
# 'i' => t_esc_sp_i
|
35
|
+
# }
|
36
|
+
# '*' => {
|
37
|
+
# 's' => t_esc_asterisk_s
|
38
|
+
# }
|
39
|
+
']' => { # OSC? -- Nope XXX TODO
|
40
|
+
[01] => {
|
41
|
+
'M' => t_osc_m # XXX TODO
|
42
|
+
'K' => t_osc_k # XXX TODO
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
'\034' => t_dim_on
|
47
|
+
'\035' => t_dim_off
|
48
|
+
'\036' => {
|
49
|
+
# 'C' => t_read_model_id
|
50
|
+
'D' => t_reverse_video_on
|
51
|
+
'E' => t_reverse_video_off
|
52
|
+
'F' => {
|
53
|
+
'A' => t_reset
|
54
|
+
'F' => t_erase_unprotected
|
55
|
+
# 'I' => t_delete_line
|
56
|
+
'Q' => {
|
57
|
+
* => t_set_cursor_type
|
58
|
+
}
|
59
|
+
# '\\' => t_delete_between_margins
|
60
|
+
# '@' => t_select_ansi_mode
|
61
|
+
}
|
62
|
+
# 'K' => t_delete_character
|
63
|
+
'~' => t_parse_proprietary_escape
|
64
|
+
}
|
65
|
+
'\377' => {
|
66
|
+
'\372' => t_parse_telnet_sb => {
|
67
|
+
* => t_telnet_subnegotiation
|
68
|
+
}
|
69
|
+
'\373' => {
|
70
|
+
* => t_telnet_will
|
71
|
+
}
|
72
|
+
'\374' => {
|
73
|
+
* => t_telnet_wont
|
74
|
+
}
|
75
|
+
'\375' => {
|
76
|
+
* => t_telnet_do
|
77
|
+
}
|
78
|
+
'\376' => {
|
79
|
+
* => t_telnet_dont
|
80
|
+
}
|
81
|
+
}
|
82
|
+
[\x20-\x7e] => t_printable
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# = Parser for DG410 terminal
|
2
|
+
# Copyright (C) 2010 Infonium Inc.
|
3
|
+
#
|
4
|
+
# This file is part of ScripTTY.
|
5
|
+
#
|
6
|
+
# ScripTTY is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published
|
8
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# ScripTTY is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
17
|
+
# along with ScripTTY. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require 'scriptty/term/dg410'
|
20
|
+
|
21
|
+
module ScripTTY # :nodoc:
|
22
|
+
module Term
|
23
|
+
class DG410 # reopen
|
24
|
+
class Parser
|
25
|
+
SERVER_PARSER_DEFINITION = File.read(File.join(File.dirname(__FILE__), "dg410-escapes.txt"))
|
26
|
+
CLIENT_PARSER_DEFINITION = File.read(File.join(File.dirname(__FILE__), "dg410-client-escapes.txt"))
|
27
|
+
|
28
|
+
# ScripTTY::Util::FSM object used by this parser. (Used for debugging.)
|
29
|
+
attr_reader :fsm
|
30
|
+
|
31
|
+
def initialize(options={})
|
32
|
+
@fsm = Util::FSM.new(
|
33
|
+
:definition => options[:client] ? CLIENT_PARSER_DEFINITION : SERVER_PARSER_DEFINITION,
|
34
|
+
:callback => self, :callback_method => :handle_event)
|
35
|
+
@callback = options[:callback]
|
36
|
+
@callback_method = options[:callback_method] || :call
|
37
|
+
on_unknown_sequence :error
|
38
|
+
end
|
39
|
+
|
40
|
+
# Set the behaviour of the terminal when an unknown escape sequence is
|
41
|
+
# found.
|
42
|
+
#
|
43
|
+
# This method takes either a symbol or a block.
|
44
|
+
#
|
45
|
+
# When a block is given, it is executed whenever an unknown escape
|
46
|
+
# sequence is received. The block is passed the escape sequence as a
|
47
|
+
# single string.
|
48
|
+
#
|
49
|
+
# When a symbol is given, it may be one of the following:
|
50
|
+
# [:error]
|
51
|
+
# (default) Raise a ScripTTY::Util::FSM::NoMatch exception.
|
52
|
+
# [:ignore]
|
53
|
+
# Ignore the unknown escape sequence.
|
54
|
+
def on_unknown_sequence(mode=nil, &block)
|
55
|
+
if !block and !mode
|
56
|
+
raise ArgumentError.new("No mode specified and no block given")
|
57
|
+
elsif block and mode
|
58
|
+
raise ArgumentError.new("Block and mode are mutually exclusive, but both were given")
|
59
|
+
elsif block
|
60
|
+
@on_unknown_sequence = block
|
61
|
+
elsif [:error, :ignore].include?(mode)
|
62
|
+
@on_unknown_sequence = mode
|
63
|
+
else
|
64
|
+
raise ArgumentError.new("Invalid mode #{mode.inspect}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Feed the specified byte to the terminal. Returns a string of
|
69
|
+
# bytes that should be transmitted (e.g. for TELNET negotiation).
|
70
|
+
def feed_byte(byte)
|
71
|
+
raise ArgumentError.new("input should be single byte") unless byte.is_a?(String) and byte.length == 1
|
72
|
+
begin
|
73
|
+
@fsm.process(byte)
|
74
|
+
rescue Util::FSM::NoMatch => e
|
75
|
+
@fsm.reset!
|
76
|
+
if @on_unknown_sequence == :error
|
77
|
+
raise
|
78
|
+
elsif @on_unknown_sequence == :ignore
|
79
|
+
# do nothing
|
80
|
+
elsif !@on_unknown_sequence.is_a?(Symbol) # @on_unknown_sequence is a Proc
|
81
|
+
@on_unknown_sequence.call(e.input_sequence.join)
|
82
|
+
else
|
83
|
+
raise "BUG"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
""
|
87
|
+
end
|
88
|
+
|
89
|
+
# Convenience method: Feeds several bytes to the terminal. Returns a
|
90
|
+
# string of bytes that should be transmitted (e.g. for TELNET
|
91
|
+
# negotiation).
|
92
|
+
def feed_bytes(bytes)
|
93
|
+
retvals = []
|
94
|
+
bytes.split(//n).each do |byte|
|
95
|
+
retvals << feed_byte(byte)
|
96
|
+
end
|
97
|
+
retvals.join
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def handle_event(event, fsm)
|
103
|
+
if respond_to?(event, true)
|
104
|
+
send(event, fsm)
|
105
|
+
else
|
106
|
+
@callback.__send__(@callback_method, event, fsm) if @callback
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Parse proprietary escape code, and fire the :t_proprietary_escape
|
111
|
+
# event when finished.
|
112
|
+
def t_parse_proprietary_escape(fsm)
|
113
|
+
state = 0
|
114
|
+
length = nil
|
115
|
+
header_length = 5
|
116
|
+
fsm.redirect = lambda {|fsm|
|
117
|
+
if fsm.input_sequence.length == header_length
|
118
|
+
length = fsm.input.unpack("C*")[0]
|
119
|
+
end
|
120
|
+
if length && fsm.input_sequence.length >= header_length + length
|
121
|
+
fsm.redirect = nil
|
122
|
+
fsm.fire_event(:t_proprietary_escape)
|
123
|
+
end
|
124
|
+
true
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
# IAC SB ... SE
|
129
|
+
def t_parse_telnet_sb(fsm)
|
130
|
+
# limit subnegotiation to 100 chars # FIXME - This is wrong
|
131
|
+
count = 0
|
132
|
+
fsm.redirect = lambda {|fsm| count += 1; count < 100 && fsm.input_sequence[-2..-1] != ["\377", "\360"]}
|
133
|
+
end
|
134
|
+
|
135
|
+
# Parse ANSI/DEC CSI escape sequence parameters. Pass in fsm.input_sequence
|
136
|
+
#
|
137
|
+
# Example:
|
138
|
+
# parse_csi_params("\e[H") # returns []
|
139
|
+
# parse_csi_params("\e[;H") # returns []
|
140
|
+
# parse_csi_params("\e[2J") # returns [2]
|
141
|
+
# parse_csi_params("\e[33;42;0m") # returns [33, 42, 0]
|
142
|
+
# parse_csi_params(["\e", "[", "3", "3", ";", "4" "2", ";" "0", "m"]) # same as above, but takes an array
|
143
|
+
#
|
144
|
+
# This also works with DEC escape sequences:
|
145
|
+
# parse_csi_params("\e[?1;2J") # returns [1,2]
|
146
|
+
def parse_csi_params(input_seq) # TODO - test this
|
147
|
+
seq = input_seq.join if input_seq.respond_to?(:join) # Convert array to string
|
148
|
+
unless seq =~ /\A\e\[\??([\d;]*)[^\d]\Z/n
|
149
|
+
raise "BUG"
|
150
|
+
end
|
151
|
+
$1.split(/;/n).map{|p|
|
152
|
+
if p.empty?
|
153
|
+
nil
|
154
|
+
else
|
155
|
+
p.to_i
|
156
|
+
end
|
157
|
+
}
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|