How to have a conversation with popen

Rubies:

The popen (and popen3) documentation and discussions in the 'net archives
deal with opening a program and only reading from it.

I want to have a QA session. So here’s a Ruby program (save it as “qa.rb”)
that asks a question, collects an answer, and prints it:

print 'question? '
STDOUT.flush()
answer = gets()
puts answer
STDOUT.flush()

Now that has excess flushes, but they don’t seem to help. Here’s a program
that tries to run that program, answer its question, and collect the
bounced answer. It has excess flushes too. It also cheats by knowing the
length of the question. My target program can cheat like this too:

require 'fcntl'

pipe = IO.popen( "ruby qa.rb", "r+" )
# pipe.close_write()
pipe.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)


def absorb pipe
    contents = ''

    loop do
        begin
            nu = pipe.readchar()
        rescue
            nu = nil
        end

        contents += nu.chr() if nu != nil

        break if contents.size() > 9
    end

    puts contents
end

absorb pipe

pipe.write('yo\n')
pipe.flush()

absorb pipe

Please observe I’m not asking how to popen into the ruby executable itself.
My ultimate target is a binary executable, so telling me how to change the
options of the inner ruby won’t help.

···


Phlip
http://www.greencheese.org/LucidScheming
– Got in trouble at StarBucks. I tried to order
"A double latte mocha and a body piercing." –

            rescue

Perhaps best to distinguish Errno::EWOULDBLOCK from other errors

    pipe.write('yo\n')

What are you trying to do with '' and \n ? Actually you are writing 4
characters `y', `o', `\\' and `n' when #gets (in qa.rb) expect a newline

Guy Decoux

Phlip wrote:

Rubies:

The popen (and popen3) documentation and discussions in the 'net archives
deal with opening a program and only reading from it.

I want to have a QA session. So here’s a Ruby program (save it as “qa.rb”)
that asks a question, collects an answer, and prints it:

print 'question? '
STDOUT.flush()
answer = gets()
puts answer
STDOUT.flush()

Now that has excess flushes, but they don’t seem to help. Here’s a program
that tries to run that program, answer its question, and collect the
bounced answer. It has excess flushes too. It also cheats by knowing the
length of the question. My target program can cheat like this too:

And here’s the winner:

require 'fcntl’
require ‘open3’

def pump
contents = ''
pin, pout, perr = Open3.popen3(‘ruby qa.rb’)
pin.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
pout.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
perr.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)

loop do
  retval = select([pout, perr, $stdin], nil, [pin, $stdout, $stderr], 

nil)
# puts “select returned”

  for i in retval[0]
    str = i.read(1)
    print str
    return if str == nil
    contents += str

    if contents.size() == 9 then
        pin.write("yo\n")
        print "yo\n"
    end

    STDOUT.flush()
  end
end

end

pump()

···


Phlip
http://andstuff.org/HarryPotter
– Just think: Four billion people in the
world have never received Spam… –