class CommandError < RuntimeError
end
class BaseCmd
attr_accessor :uid, :done, :status
end
class Sheller
attr_accessor :continious
def initialize(bin = "bash")
@sleep_time = 0.001
@input_pipe = IO.pipe
@output_pipe = IO.pipe
@error_pipe = IO.pipe
@invalid = false
fork do
@input_pipe[1].close
@output_pipe[0].close
@error_pipe[0].close
$stdin.reopen(@input_pipe[0])
$stdout.reopen(@output_pipe[1])
$stderr.reopen(@error_pipe[1])
exec(bin)
end
@input_pipe[0].close
@output_pipe[1].close
@error_pipe[1].close
end
def low_write(data)
printf "#{data}" if $DEBUG
@input_pipe[1].write(data)
end
def write(data)
low_write(data)
low_write("echo -e \"\027:$?\" > /dev/stderr\n")
end
def poll
clean = true
if svrs = IO.select([@output_pipe[0]], nil, nil, 0)
svrs[0].each { |io|
clean = false
line = io.readline.chomp
got_stdout(line)
}
end
if svrs = IO.select([@error_pipe[0]], nil, nil, 0)
svrs[0].each { |io|
clean = false
line = io.readline
if line[0] == 23
md = line.match(/^.:(\d+)$/)
if md
@pending_cmd.status = md[1].to_i
raise CommandError if @pending_cmd.status != 0 && @continious
end
else
got_stderr(line)
end
}
end
if @pending_cmd.status and clean
@pending_cmd.done = true
end
end
def read_loop
while !@pending_cmd.done
poll
sleep(@sleep_time)
end
end
def do(string)
@pending_cmd = BaseCmd.new
begin
write("%s\n" % string)
read_loop
rescue EOFError,Errno::EPIPE => error
Process.wait
# $?.exitstatus
@invalid = true
return nil
end
return @pending_cmd
end
def info(string)
puts "# %s" % [string]
end
def got_stdout(line)
end
def got_stderr(line)
end
end