scriptty 0.5.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitattributes +1 -0
  2. data/.gitignore +3 -0
  3. data/COPYING +674 -0
  4. data/COPYING.LESSER +165 -0
  5. data/README.rdoc +31 -0
  6. data/Rakefile +49 -0
  7. data/VERSION +1 -0
  8. data/bin/scriptty-capture +5 -0
  9. data/bin/scriptty-dump-screens +4 -0
  10. data/bin/scriptty-replay +5 -0
  11. data/bin/scriptty-term-test +4 -0
  12. data/bin/scriptty-transcript-parse +4 -0
  13. data/examples/captures/xterm-overlong-line-prompt.bin +9 -0
  14. data/examples/captures/xterm-vim-session.bin +262 -0
  15. data/examples/demo-capture.rb +19 -0
  16. data/examples/telnet-nego.rb +55 -0
  17. data/lib/scriptty/apps/capture_app/console.rb +104 -0
  18. data/lib/scriptty/apps/capture_app/password_prompt.rb +65 -0
  19. data/lib/scriptty/apps/capture_app.rb +213 -0
  20. data/lib/scriptty/apps/dump_screens_app.rb +166 -0
  21. data/lib/scriptty/apps/replay_app.rb +229 -0
  22. data/lib/scriptty/apps/term_test_app.rb +124 -0
  23. data/lib/scriptty/apps/transcript_parse_app.rb +143 -0
  24. data/lib/scriptty/cursor.rb +39 -0
  25. data/lib/scriptty/exception.rb +38 -0
  26. data/lib/scriptty/expect.rb +392 -0
  27. data/lib/scriptty/multiline_buffer.rb +192 -0
  28. data/lib/scriptty/net/event_loop.rb +610 -0
  29. data/lib/scriptty/screen_pattern/generator.rb +398 -0
  30. data/lib/scriptty/screen_pattern/parser.rb +558 -0
  31. data/lib/scriptty/screen_pattern.rb +104 -0
  32. data/lib/scriptty/term/dg410/dg410-client-escapes.txt +37 -0
  33. data/lib/scriptty/term/dg410/dg410-escapes.txt +82 -0
  34. data/lib/scriptty/term/dg410/parser.rb +162 -0
  35. data/lib/scriptty/term/dg410.rb +489 -0
  36. data/lib/scriptty/term/xterm/xterm-escapes.txt +73 -0
  37. data/lib/scriptty/term/xterm.rb +661 -0
  38. data/lib/scriptty/term.rb +40 -0
  39. data/lib/scriptty/util/fsm/definition_parser.rb +111 -0
  40. data/lib/scriptty/util/fsm/scriptty_fsm_definition.treetop +189 -0
  41. data/lib/scriptty/util/fsm.rb +177 -0
  42. data/lib/scriptty/util/transcript/reader.rb +96 -0
  43. data/lib/scriptty/util/transcript/writer.rb +111 -0
  44. data/test/apps/capture_app_test.rb +123 -0
  45. data/test/apps/transcript_parse_app_test.rb +118 -0
  46. data/test/cursor_test.rb +51 -0
  47. data/test/fsm_definition_parser_test.rb +220 -0
  48. data/test/fsm_test.rb +322 -0
  49. data/test/multiline_buffer_test.rb +275 -0
  50. data/test/net/event_loop_test.rb +402 -0
  51. data/test/screen_pattern/generator_test.rb +408 -0
  52. data/test/screen_pattern/parser_test/explicit_cursor_pattern.txt +14 -0
  53. data/test/screen_pattern/parser_test/explicit_fields.txt +22 -0
  54. data/test/screen_pattern/parser_test/multiple_patterns.txt +42 -0
  55. data/test/screen_pattern/parser_test/simple_pattern.txt +14 -0
  56. data/test/screen_pattern/parser_test/truncated_heredoc.txt +12 -0
  57. data/test/screen_pattern/parser_test/utf16bebom_pattern.bin +0 -0
  58. data/test/screen_pattern/parser_test/utf16lebom_pattern.bin +0 -0
  59. data/test/screen_pattern/parser_test/utf8_pattern.bin +14 -0
  60. data/test/screen_pattern/parser_test/utf8_unix_pattern.bin +14 -0
  61. data/test/screen_pattern/parser_test/utf8bom_pattern.bin +14 -0
  62. data/test/screen_pattern/parser_test.rb +266 -0
  63. data/test/term/dg410/parser_test.rb +139 -0
  64. data/test/term/xterm_test.rb +327 -0
  65. data/test/test_helper.rb +3 -0
  66. data/test/util/transcript/reader_test.rb +131 -0
  67. data/test/util/transcript/writer_test.rb +126 -0
  68. data/test.watchr +29 -0
  69. metadata +175 -0
@@ -0,0 +1,229 @@
1
+ # = Fake server that replays transcripts to a client
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 'optparse'
20
+ require 'scriptty/net/event_loop'
21
+ require 'scriptty/util/transcript/reader'
22
+ require 'scriptty/term'
23
+ require 'logger'
24
+ require 'stringio'
25
+
26
+ module ScripTTY
27
+ module Apps
28
+ class ReplayApp
29
+ attr_reader :term
30
+
31
+ def initialize(argv)
32
+ @client_connection = nil
33
+ @server_connection = nil
34
+ @output_file = nil
35
+ @options = parse_options(argv)
36
+ @console_password = "" # TODO SECURITY FIXME
37
+ @attached_consoles = []
38
+ @log_stringio = StringIO.new
39
+ @log = Logger.new(@log_stringio)
40
+ @net = ScripTTY::Net::EventLoop.new
41
+ @input_transcript = []
42
+ @last_command = nil
43
+ end
44
+
45
+ def detach_console(console)
46
+ @attached_consoles.delete(console)
47
+ end
48
+
49
+ def log_messages
50
+ ([""]*10 + @log_stringio.string.split("\n"))[-10..-1].map{|line| line.sub(/^.*?\]/, '')}
51
+ end
52
+
53
+ def main
54
+ @output_file = Util::Transcript::Writer.new(File.open(@options[:output], "w")) if @options[:output]
55
+ @net.on_accept(@options[:console_addrs] || [], :multiple => true) do |conn|
56
+ p = CaptureApp::PasswordPrompt.new(conn, "Console password: ")
57
+ p.authenticate { |password| password == @console_password }
58
+ p.on_fail { conn.write("Authentiation failed.\r\n") { conn.close } }
59
+ p.on_success {
60
+ @attached_consoles << CaptureApp::Console.new(conn, self)
61
+ @attached_consoles.each { |c| c.refresh! }
62
+ }
63
+ end
64
+ @net.on_accept(@options[:listen_addrs], :multiple => true) do |conn|
65
+ @output_file.client_open(*conn.remote_address) if @output_file
66
+ @client_connection = conn
67
+ @client_connection.on_receive_bytes { |bytes| handle_client_receive_bytes(bytes) }
68
+ @client_connection.on_close { handle_client_close ; @client_connection = nil }
69
+ handle_client_connected
70
+ end
71
+ @net.main
72
+ ensure
73
+ if @output_file
74
+ @output_file.close
75
+ @output_file = nil
76
+ end
77
+ end
78
+
79
+ def handle_console_command_entered(cmd)
80
+ case cmd
81
+ when /^$/ # repeat last command
82
+ if @last_command
83
+ handle_console_command_entered(@last_command)
84
+ else
85
+ log.warn("No previous command entered")
86
+ end
87
+ return nil
88
+ when /^(\d*)(n|next)$/i # replay next step
89
+ count = $1 ? $1.to_i : 1
90
+ count.times { replay_next }
91
+ else
92
+ log.warn("Unknown console command: #{cmd}")
93
+ end
94
+ @last_command = cmd
95
+ end
96
+
97
+ # Instruct the event loop to exit.
98
+ #
99
+ # Can be invoked by another thread.
100
+ def exit
101
+ @net.exit
102
+ end
103
+
104
+ private
105
+
106
+ attr_reader :log
107
+
108
+ def handle_client_connected
109
+ @term = ScripTTY::Term.new(@options[:term])
110
+ @term.on_unknown_sequence do |sequence|
111
+ log.debug("Unknown escape sequence: #{sequence.inspect}")
112
+ end
113
+ replay_start
114
+ replay_next
115
+ refresh_consoles
116
+ end
117
+
118
+ def handle_client_receive_bytes(bytes)
119
+ log.info("Received from client: #{bytes.inspect}")
120
+ refresh_consoles
121
+ end
122
+
123
+ def handle_client_close
124
+ log.info("Client connection closed")
125
+ refresh_consoles
126
+ end
127
+
128
+ def replay_start
129
+ @next_bytes_to_send = nil
130
+ @transcript = []
131
+ @options[:input_files].each do |filename|
132
+ @transcript << ["--- File: #{filename} ---", nil]
133
+ reader = Util::Transcript::Reader.new
134
+ File.open(filename, "r") do |infile|
135
+ line_num = 0
136
+ until infile.eof?
137
+ line_num += 1
138
+ line = infile.readline
139
+ timestamp, type, args = reader.parse_line(line)
140
+ if type == :from_server
141
+ @transcript << ["(#{line_num}) #{line.strip}", args[0]]
142
+ elsif type == :server_parsed
143
+ @transcript << ["(#{line_num}) #{line.strip}", args[1]]
144
+ else
145
+ @transcript << ["(#{line_num}) #{line.strip}", nil]
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ def replay_next
153
+ if @next_bytes_to_send
154
+ @client_connection.write(@next_bytes_to_send) { refresh_consoles }
155
+ @term.feed_bytes(@next_bytes_to_send)
156
+ @next_bytes_to_send = nil
157
+ end
158
+ until @transcript.empty?
159
+ display, bytes = @transcript.shift
160
+ if bytes
161
+ log.debug("NXTD: #{display}") # next data
162
+ @next_bytes_to_send = bytes
163
+ break
164
+ else
165
+ log.debug("INFO: #{display}")
166
+ end
167
+ end
168
+ if @transcript.empty?
169
+ log.debug("DONE")
170
+ end
171
+ end
172
+
173
+ def refresh_consoles
174
+ @attached_consoles.each { |c| c.refresh! }
175
+ end
176
+
177
+ def parse_options(argv)
178
+ args = argv.dup
179
+ options = {:listen_addrs => [], :console_addrs => []}
180
+ opts = OptionParser.new do |opts|
181
+ opts.banner = "Usage: #{opts.program_name} [options] FILE"
182
+ opts.separator "Stream capture application"
183
+ opts.on("-l", "--listen [HOST]:PORT", "Listen on the specified HOST:PORT") do |optarg|
184
+ addr = parse_hostport(optarg, :allow_empty_host => true, :allow_zero_port => true)
185
+ options[:listen_addrs] << addr
186
+ end
187
+ opts.on("-C", "--console [HOST]:PORT", "Debug console on the specified HOST:PORT") do |optarg|
188
+ addr = parse_hostport(optarg, :allow_empty_host => true, :allow_zero_port => true)
189
+ options[:console_addrs] << addr
190
+ end
191
+ opts.on("-t", "--term NAME", "Terminal to emulate") do |optarg|
192
+ raise ArgumentError.new("Unsupported terminal #{optarg.inspect}") unless ScripTTY::Term::TERMINAL_TYPES.include?(optarg)
193
+ options[:term] = optarg
194
+ end
195
+ end
196
+ opts.parse!(args)
197
+ if args.length < 1
198
+ $stderr.puts "error: No input file(s) specified."
199
+ exit 1
200
+ end
201
+ unless !options[:listen_addrs].empty? and !options[:console_addrs].empty? and options[:term]
202
+ $stderr.puts "error: --listen, --console, and --term are mandatory"
203
+ exit 1
204
+ end
205
+ options[:input_files] = args
206
+ options
207
+ end
208
+
209
+ # Parse [HOST:]PORT into separate host and port. Host is optional, and
210
+ # might be surrounded by square brackets.
211
+ def parse_hostport(s, opts={})
212
+ unless s =~ /\A(\[[^\[\]]*\]|[^\[\]]*):(\d+)\Z/
213
+ raise ArgumentError.new("Unable to parse host:port")
214
+ end
215
+ host, port = [$1, $2]
216
+ host.gsub!(/\A\[(.*?)\]\Z/, '\1')
217
+ port = port.to_i
218
+ raise ArgumentError.new("Invalid port") if port < 0 or port > 0xffff or (port == 0 and !opts[:allow_zero_port])
219
+ unless opts[:allow_empty_host]
220
+ raise ArgumentError.new("Host cannot be empty") if host.empty?
221
+ end
222
+ [host, port]
223
+ end
224
+ end
225
+ end
226
+ end
227
+
228
+ require 'scriptty/apps/capture_app/password_prompt'
229
+ require 'scriptty/apps/capture_app/console'
@@ -0,0 +1,124 @@
1
+ # = Terminal emulation testing app
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 'optparse'
20
+ require 'scriptty/term'
21
+ require 'scriptty/util/transcript/reader'
22
+
23
+ module ScripTTY
24
+ module Apps
25
+ class TermTestApp
26
+ def initialize(argv)
27
+ @options = parse_options(argv)
28
+ end
29
+
30
+ def log(message)
31
+ @log_buffer << message
32
+ @log_file.puts(message) if @log_file
33
+ end
34
+
35
+ def main
36
+ @log_buffer = []
37
+ @log_file = @options[:log] && File.open(@options[:log], "w")
38
+ @term = ScripTTY::Term.new(@options[:term])
39
+ @term.on_unknown_sequence do |seq|
40
+ log "Unknown escape sequence: #{seq.inspect}"
41
+ end
42
+ $stdout.print "\ec" # Reset terminal; clear the screen
43
+ $stdout.flush
44
+ time_multiplier = @options[:rate] > 0 ? 1.0/@options[:rate] : 0
45
+ @options[:input_files].each do |inp|
46
+ File.open(inp[:path], "rb") do |input_file|
47
+ time0 = Time.now
48
+ timestamp0 = timestamp = nil
49
+ reader = Util::Transcript::Reader.new
50
+ until input_file.eof?
51
+ # Read a chunk of the input file
52
+ case inp[:format]
53
+ when :binary
54
+ c = input_file.read(1)
55
+ @term.feed_byte(c)
56
+ when :capture
57
+ timestamp, type, args = reader.parse_line(input_file.readline)
58
+ next unless type == :from_server
59
+ bytes = args[0]
60
+
61
+ # Wait until the time specified in the timestamp passes
62
+ timestamp0 = timestamp unless timestamp0 # treat the first timestamp as time 0
63
+ sleep_time = (timestamp-timestamp0)*time_multiplier - (Time.now - time0)
64
+ sleep(sleep_time) if sleep_time > 0
65
+
66
+ @term.feed_bytes(bytes)
67
+ else
68
+ raise "BUG: Invalid format: #{inp[:format]}"
69
+ end
70
+
71
+ # Output the screen contents
72
+ screen_lines = []
73
+ screen_lines << "Timestamp: #{timestamp}" if timestamp
74
+ screen_lines << "Cursor position: #{@term.cursor_pos.inspect}"
75
+ screen_lines += @term.debug_info if @term.respond_to?(:debug_info)
76
+ screen_lines << "+" + "-"*@term.width + "+"
77
+ @term.text.each do |line|
78
+ screen_lines << "|#{line}|"
79
+ end
80
+ screen_lines << "+" + "-"*@term.width + "+"
81
+ screen_lines << "--- Log ---"
82
+ ([0,@log_buffer.length-10].max..@log_buffer.length-1).each do |i|
83
+ screen_lines << sprintf("%3d: %s", i+1, @log_buffer[i])
84
+ end
85
+ screen_lines << "--- End of log ---"
86
+ screen_lines << ""
87
+ $stdout.puts "\e[H" + screen_lines.map{|line| "\e[2K" + line}.join("\n")
88
+ $stdout.flush
89
+ end
90
+ end
91
+ end
92
+ @log_file.close if @log_file
93
+ end
94
+
95
+ private
96
+ def parse_options(argv)
97
+ args = argv.dup
98
+ options = {:term => 'xterm', :input_files => [], :rate => 2}
99
+ opts = OptionParser.new do |opts|
100
+ opts.banner = "Usage: #{opts.program_name} [options]"
101
+ opts.separator "Debug a specified terminal emulator"
102
+ opts.on("-t", "--term NAME", "Terminal to emulate") do |optarg|
103
+ raise ArgumentError.new("Unsupported terminal #{optarg.inspect}") unless ScripTTY::Term::TERMINAL_TYPES.include?(optarg)
104
+ options[:term] = optarg
105
+ end
106
+ opts.on("-b", "--binary-input FILE", "Binary file to read") do |optarg|
107
+ options[:input_files] << {:path => optarg, :format => :binary}
108
+ end
109
+ opts.on("-c", "--capture-input FILE", "Capture-format file to read") do |optarg|
110
+ options[:input_files] << {:path => optarg, :format => :capture}
111
+ end
112
+ opts.on("-r", "--rate RATE", "Playback at the specified rate (0 for infinite; default: #{options[:rate]})") do |optarg|
113
+ options[:rate] = optarg.to_f
114
+ end
115
+ opts.on("-L", "--log FILE", "Write log to FILE") do |optarg|
116
+ options[:log] = optarg
117
+ end
118
+ end
119
+ opts.parse!(args)
120
+ options
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,143 @@
1
+ # = Transcript parsing app
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 'optparse'
20
+ require 'scriptty/term'
21
+ require 'scriptty/util/transcript/reader'
22
+ require 'scriptty/util/transcript/writer'
23
+
24
+ module ScripTTY
25
+ module Apps
26
+ class TranscriptParseApp
27
+ def initialize(argv)
28
+ @options = parse_options(argv)
29
+ end
30
+
31
+ def main
32
+ File.open(@options[:output], "w") do |output_file|
33
+ @writer = ScripTTY::Util::Transcript::Writer.new(output_file)
34
+ @options[:input_files].each do |input_filename|
35
+ File.open(input_filename, "rb") do |input_file|
36
+ reader = ScripTTY::Util::Transcript::Reader.new
37
+ @last_printable = nil
38
+ parser_class = ScripTTY::Term.class_by_name(@options[:term]).parser_class
39
+
40
+ # Set up server-side FSM
41
+ @server_parser = parser_class.new :callback => Proc.new { |event_name, fsm|
42
+ if event_name == :t_printable
43
+ # Merge printable character sequences together, rather than writing individual "t_printable" events.
44
+ @last_server_printable ||= ""
45
+ @last_server_printable += fsm.input_sequence.join
46
+ else
47
+ flush_server_printable
48
+ @writer.server_parsed(event_name, fsm.input_sequence.join)
49
+ end
50
+ }
51
+ @server_parser.on_unknown_sequence { |seq| @writer.server_parsed("?", seq) }
52
+
53
+ # Set up client-side FSM
54
+ if @options[:client]
55
+ @client_parser = parser_class.new :client => true, :callback => Proc.new { |event_name, fsm|
56
+ if event_name == :t_printable
57
+ # Merge printable character sequences together, rather than writing individual "t_printable" events.
58
+ @last_client_printable ||= ""
59
+ @last_client_printable += fsm.input_sequence.join
60
+ else
61
+ flush_client_printable
62
+ @writer.client_parsed(event_name, fsm.input_sequence.join)
63
+ end
64
+ }
65
+ @client_parser.on_unknown_sequence { |seq| @writer.client_parsed("?", seq) }
66
+ end
67
+
68
+ until input_file.eof?
69
+ timestamp, type, args = reader.parse_line(input_file.readline)
70
+ @writer.override_timestamp = timestamp
71
+ if type == :from_server
72
+ @writer.send(type, *args) if @options[:keep]
73
+ bytes = args[0]
74
+ @server_parser.feed_bytes(bytes)
75
+ elsif type == :from_client and @client_parser
76
+ @writer.send(type, *args) if @options[:keep]
77
+ bytes = args[0]
78
+ @client_parser.feed_bytes(bytes)
79
+ else
80
+ @writer.send(type, *args)
81
+ end
82
+ end
83
+ flush_server_printable
84
+ flush_client_printable if @client_parser
85
+ end
86
+ end
87
+ @writer.close
88
+ end
89
+ end
90
+
91
+ private
92
+
93
+ def flush_server_printable
94
+ if @last_server_printable
95
+ @writer.server_parsed(".", @last_server_printable)
96
+ @last_server_printable = nil
97
+ end
98
+ end
99
+
100
+ def flush_client_printable
101
+ if @last_client_printable
102
+ @writer.client_parsed(".", @last_client_printable)
103
+ @last_client_printable = nil
104
+ end
105
+ end
106
+
107
+ def parse_options(argv)
108
+ args = argv.dup
109
+ options = {:input_files => []}
110
+ opts = OptionParser.new do |opts|
111
+ opts.banner = "Usage: #{opts.program_name} [options] FILE..."
112
+ opts.separator "Parse transcript escape sequences according to a specified terminal emulation,"
113
+ opts.separator 'converting raw "S" transcript entries into parsed "Sp" entries.'
114
+
115
+ opts.on("-t", "--term NAME", "Terminal to emulate") do |optarg|
116
+ raise ArgumentError.new("Unsupported terminal #{optarg.inspect}") unless ScripTTY::Term::TERMINAL_TYPES.include?(optarg)
117
+ options[:term] = optarg
118
+ end
119
+ opts.on("-k", "--keep", 'Keep original "S" lines in the transcript') do |optarg|
120
+ options[:keep] = optarg
121
+ end
122
+ opts.on("-c", "--[no-]client", "Also parse client (\"C\") entries") do |optarg|
123
+ options[:client] = optarg
124
+ end
125
+ opts.on("-o", "--output FILE", "Write output to FILE") do |optarg|
126
+ options[:output] = optarg
127
+ end
128
+ end
129
+ opts.parse!(args)
130
+ if args.length < 1
131
+ $stderr.puts "error: No input file(s) specified."
132
+ exit 1
133
+ end
134
+ unless options[:output] and options[:term]
135
+ $stderr.puts "error: --output and --term are mandatory"
136
+ exit 1
137
+ end
138
+ options[:input_files] = args
139
+ options
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,39 @@
1
+ # = Cursor object
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
+ module ScripTTY
20
+ class Cursor
21
+ attr_accessor :row, :column
22
+ def initialize
23
+ @row = 0
24
+ @column = 0
25
+ end
26
+
27
+ def pos
28
+ [@row, @column]
29
+ end
30
+
31
+ def pos=(value)
32
+ raise TypeError.new("must be 2-element array") unless value.is_a?(Array) and value.length == 2
33
+ @row, @column = value
34
+ @row ||= 0
35
+ @column ||= 0
36
+ value
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,38 @@
1
+ # = ScripTTY exceptions
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
+ module ScripTTY
20
+ module Exception
21
+ # Exception base class
22
+ class Base < StandardError
23
+ end
24
+
25
+ # Raised when a script times out.
26
+ class Timeout < Base
27
+ end
28
+
29
+ # Raised when a connection error occurs
30
+ class ConnectError < Base
31
+ attr_accessor :orig_exception
32
+ def initialize(exception)
33
+ @orig_exception = exception
34
+ super("Connect error (#{exception.class.name}): #{exception}")
35
+ end
36
+ end
37
+ end
38
+ end