class SystemUniversal

def self.ruby

def self.ruby
  return @ruby if @ruby
  c = begin; ::RbConfig::CONFIG; rescue NameError; ::Config::CONFIG; end
  ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
  @ruby = if system('%s -e 42' % ruby)
    ruby
  else
    system('%s -e 42' % 'ruby') ? 'ruby' : warn('no ruby in PATH/CONFIG')
  end
end

def child_program config

def child_program config
  <<-program
    # encoding: utf-8
    PIPE = STDOUT.dup
    begin
      config = Marshal.load(IO.read('#{ config }',:mode=>"rb"))
      argv = config['argv']
      env = config['env']
      cwd = config['cwd']
      stdin = config['stdin']
      stdout = config['stdout']
      stderr = config['stderr']
      Dir.chdir cwd if cwd
      env.each{|k,v| ENV[k.to_s] = v.to_s} if env
      STDIN.reopen stdin
      STDOUT.reopen stdout
      STDERR.reopen stderr
      PIPE.puts "pid: \#{ Process.pid }"
      PIPE.flush                        ### the process is ready yo!
      PIPE.close
      exec *argv
    rescue Exception => e
      PIPE.write Marshal.dump(e) rescue nil
      exit 42
    end
  program
end

def child_setup tmp

def child_setup tmp
  stdin = File.expand_path(File.join(tmp, 'stdin'))
  stdout = File.expand_path(File.join(tmp, 'stdout'))
  stderr = File.expand_path(File.join(tmp, 'stderr'))
  program = File.expand_path(File.join(tmp, 'program'))
  config = File.expand_path(File.join(tmp, 'config'))
  if @stdin
    open(stdin, 'wb'){|f| relay @stdin => f}
  else
    FileUtils.touch stdin
  end
  FileUtils.touch stdout
  FileUtils.touch stderr
  c = {}
  c['argv'] = @argv
  c['env'] = @env
  c['cwd'] = @cwd
  c['stdin'] = stdin
  c['stdout'] = stdout
  c['stderr'] = stderr
  c['program'] = program
  open(config, 'wb'){|f| Marshal.dump(c, f)}
  open(program, 'wb'){|f| f.write child_program(config)}
  c
end

def getopts opts = {}

def getopts opts = {}
  lambda do |*args|
    keys, default, _ = args
    catch(:opt) do
      [keys].flatten.each do |key|
        [key, key.to_s, key.to_s.intern].each do |k|
          throw :opt, opts[k] if opts.has_key?(k)
        end
      end
      default
    end
  end
end

def initialize argv, opts = {}, &block

def initialize argv, opts = {}, &block
  getopt = getopts opts
  @argv = argv
  @block = block
  @stdin = getopt[ ['stdin', 'in', '0', 0] ]
  @stdout = getopt[ ['stdout', 'out', '1', 1] ]
  @stderr = getopt[ ['stderr', 'err', '2', 2] ]
  @env = getopt[ 'env' ]
  @cwd = getopt[ 'cwd' ]
  @host = getopt[ 'host', self.class.host ]
  @ppid = getopt[ 'ppid', self.class.ppid ]
  @pid = getopt[ 'pid', self.class.pid ]
  @ruby = getopt[ 'ruby', self.class.ruby ]
end

def new_thread child_pid, block

def new_thread child_pid, block
  q = Queue.new
  Thread.new(child_pid) do |cid|
    current = Thread.current
    current.abort_on_exception = true
    q.push current
    block.call cid
  end
  q.pop
end

def quietly

def quietly
  v = $VERBOSE
  $VERBOSE = nil
  yield
ensure
  $VERBOSE = v
end

def quote(*words)

def quote(*words)
  words.map{|word| word.inspect}.join(' ')
end

def quote *args, &block

def quote *args, &block
  SystemUniversal.quote(*args, &block)
end

def relay srcdst

def relay srcdst
  src, dst, _ = srcdst.to_a.first
  if src.respond_to? 'read'
    while((buffer = src.read(8192))); dst << buffer; end
  else
    if src.respond_to?(:each_line)
      src.each_line{|buf| dst << buf}
    else
      src.each{|buf| dst << buf}
    end
  end
end

def slug_for(*args)

def slug_for(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  join = (options[:join] || options['join'] || '_').to_s
  string = args.flatten.compact.join(join)
  words = string.to_s.scan(%r|[/\w]+|)
  words.map!{|word| word.gsub %r|[^/0-9a-zA-Z_-]|, ''}
  words.delete_if{|word| word.nil? or word.strip.empty?}
  words.join(join).downcase.gsub('/', (join * 2))
end

def systemu

def systemu
  tmpdir do |tmp|
    c = child_setup tmp
    status = nil
    begin
      thread = nil
      quietly{
        IO.popen "#{ quote(@ruby) } #{ quote(c['program']) }", 'rb+' do |pipe|
          line = pipe.gets
          case line
            when %r/^pid: \d+$/
              cid = Integer line[%r/\d+/]
            else
              begin
                buf = pipe.read
                buf = "#{ line }#{ buf }"
                e = Marshal.load buf
                raise unless Exception === e
                raise e
              rescue
                raise "systemu: Error - process interrupted!\n#{ buf }\n"
              end
          end
          thread = new_thread cid, @block if @block
          pipe.read rescue nil
        end
      }
      status = $?
    ensure
      if thread
        begin
          class << status
            attr 'thread'
          end
          status.instance_eval{ @thread = thread }
        rescue
          42
        end
      end
    end
    if @stdout or @stderr
      open(c['stdout'], 'rb'){|f| relay f => @stdout} if @stdout
      open(c['stderr'], 'rb'){|f| relay f => @stderr} if @stderr
      status
    else
      [status, open(c['stdout'], 'rb'){|f| f.read}, open(c['stderr'], 'rb'){|f| f.read}]
    end
  end
end

def systemu

def systemu
  split_argv = JRuby::PathHelper.smart_split_command @argv
  process = java.lang.Runtime.runtime.exec split_argv.to_java(:string)
  stdout, stderr = [process.input_stream, process.error_stream].map do |stream|
    StreamReader.new(stream)
  end
  field = process.get_class.get_declared_field("pid")
  field.set_accessible(true)
  pid = field.get(process)
  thread = new_thread pid, @block if @block
  exit_code = process.wait_for
  [
    RubyProcess::RubyStatus.new_process_status(JRuby.runtime, exit_code, pid),
    stdout.join,
    stderr.join
  ]
end

def tmpdir d = Dir.tmpdir, max = 42, &b

def tmpdir d = Dir.tmpdir, max = 42, &b
  i = -1 and loop{
    i += 1
    tmp = File.join(d, slug_for("systemu_#{ @host }_#{ @ppid }_#{ @pid }_#{ rand }_#{ i += 1 }"))
    begin
      Dir.mkdir tmp
    rescue Errno::EEXIST
      raise if i >= max
      next
    end
    break(
      if b
        begin
          b.call tmp
        ensure
          FileUtils.rm_rf tmp unless SystemU.turd
        end
      else
        tmp
      end
    )
  }
end

def version() SystemUniversal::VERSION end

def version() SystemUniversal::VERSION end