2012-06-29 05:18:28 +00:00
# -*- coding: binary -*-
2005-07-14 22:45:10 +00:00
require 'rex/ui'
module Rex
module Ui
module Text
2012-05-24 23:10:26 +00:00
begin
2005-07-14 22:45:10 +00:00
2013-08-30 21:28:33 +00:00
###
#
# This class implements standard input using readline against
# standard input. It supports tab completion.
#
###
class Input :: Readline < Rex :: Ui :: Text :: Input
#
# Initializes the readline-aware Input instance for text.
#
def initialize ( tab_complete_proc = nil )
if ( not Object . const_defined? ( 'Readline' ) )
2014-10-29 21:26:36 +00:00
require 'readline'
2013-08-30 21:28:33 +00:00
end
self . extend ( :: Readline )
if ( tab_complete_proc )
:: Readline . basic_word_break_characters = " \x00 "
:: Readline . completion_proc = tab_complete_proc
@rl_saved_proc = tab_complete_proc
end
end
#
# Reattach the original completion proc
#
def reset_tab_completion ( tab_complete_proc = nil )
:: Readline . basic_word_break_characters = " \x00 "
:: Readline . completion_proc = tab_complete_proc || @rl_saved_proc
end
#
# Whether or not the input medium supports readline.
#
def supports_readline
true
end
#
# Calls sysread on the standard input handle.
#
def sysread ( len = 1 )
begin
self . fd . sysread ( len )
rescue :: Errno :: EINTR
retry
end
end
#
# Read a line from stdin
#
def gets ( )
begin
self . fd . gets ( )
rescue :: Errno :: EINTR
retry
end
end
#
# Stick readline into a low-priority thread so that the scheduler doesn't slow
# down other background threads. This is important when there are many active
# background jobs, such as when the user is running Karmetasploit
#
def pgets ( )
line = nil
orig = Thread . current . priority
begin
Thread . current . priority = - 20
output . prompting
2014-12-08 20:31:00 +00:00
line = readline_with_output ( prompt , true )
2013-08-30 21:28:33 +00:00
:: Readline :: HISTORY . pop if ( line and line . empty? )
ensure
Thread . current . priority = orig || 0
end
line
end
#
# Returns the output pipe handle
#
def fd
$stdin
end
#
# Indicates that this input medium as a shell builtin, no need
# to extend.
#
def intrinsic_shell?
true
end
#
# The prompt that is to be displayed.
#
attr_accessor :prompt
#
# The output handle to use when displaying the prompt.
#
attr_accessor :output
2014-12-08 20:31:00 +00:00
private
def readline_with_output ( prompt , add_history = false )
# rb-readlines's Readline.readline hardcodes the input and output to $stdin and $stdout, which means setting
# `Readline.input` or `Readline.ouput` has no effect when running `Readline.readline` with rb-readline, so need
# to reimplement []`Readline.readline`](https://github.com/luislavena/rb-readline/blob/ce4908dae45dbcae90a6e42e3710b8c3a1f2cd64/lib/readline.rb#L36-L58)
# for rb-readline to support setting input and output. Output needs to be set so that colorization works for the
# prompt on Windows.
if defined? RbReadline
RbReadline . rl_instream = fd
RbReadline . rl_outstream = output
begin
line = RbReadline . readline ( prompt )
rescue :: Exception = > exception
RbReadline . rl_cleanup_after_signal ( )
RbReadline . rl_deprep_terminal ( )
raise exception
end
if add_history && line
RbReadline . add_history ( line )
end
line . try ( :dup )
else
:: Readline . readline ( prompt , true )
end
end
2013-08-30 21:28:33 +00:00
end
2005-07-14 22:45:10 +00:00
rescue LoadError
end
end
end
2008-11-09 08:44:36 +00:00
end