Pipe in cmd-line text but then reset STDIN for menu

Hello,
I'm trying to make a customized pager utility that can process
file-contents piped in from the command line, equally well as a list of
provided file names.
e.g. cat testfile | my_util.rb or my_util.rb testfile

I'm having trouble using the pipe to get the file contents and still be
able to use STDIN in a non-blocking way for a shell-style interactive
menu.

For the menu, I'm using Highline::SystemExtensions: e.g.:
while (mychar = get_character) && (mychar.chr != "q")
  if (mychar.chr == "x") then
    filter_all_but_selected
  end
end

... and that works only for the case where there is no input pipe,
instead filename(s) I get from ARGV.

Here's what I've tried to get the pipe read before begining the menu,
but thid hammers the rest of my script and my highline menu doesn't
work:

def fill_pipe
  # capture piped input
  flags = STDIN.fcntl(Fcntl::F_GETFL, 0)
  flags |= Fcntl::O_NONBLOCK
  STDIN.fcntl(Fcntl::F_SETFL, flags)
  begin
    input_pipe = STDIN.readlines
    $working_pipe.concat(input_pipe)
# puts "Input pipe: #{$input_pipe}"
  rescue Errno::EAGAIN
    puts "ERROR: no input piped nor file name provided"
    display_help
  end # end what kind of input
end # end fill_pipe

STDIN.close_read doesn't do the trick to reset things -- ideas how I
can have it both ways? Thanks! Andrew.

···

--
Posted via http://www.ruby-forum.com/.

Andrew Seidel wrote:

I'm having trouble using the pipe to get the file contents and still be
able to use STDIN in a non-blocking way for a shell-style interactive
menu.

I think what you're asking is: how can I write a program which does the
same as this?

    cat /usr/share/file/magic | less

(i.e. less reads its input from stdin, but can also read the terminal).

This is more a Unix question than a Ruby one. Probably the easiest way
to find out will be to read the source code of 'less'.

The less manpage directs you to http://www.greenwoodsoftware.com/less/
from where you can download the source tarball.

The relevant bit:

        /*
         * Try /dev/tty.
         * If that doesn't work, use file descriptor 2,
         * which in Unix is usually attached to the screen,
         * but also usually lets you read from the keyboard.
         */
#if OS2
        /* The __open() system call translates "/dev/tty" to "con". */
        tty = __open("/dev/tty", OPEN_READ);
#else
        tty = open("/dev/tty", OPEN_READ);
#endif
        if (tty < 0)
                tty = 2;

That is: it opens /dev/tty for keyboard input, and falls back to fd 2 if
that fails. In Ruby that would be something like

  mystdin = IO.open("/dev/tty") rescue IO.for_fd(2)

or if your user library can only talk to STDIN, then perhaps

  STDIN.reopen("/dev/tty")

All untested.

···

--
Posted via http://www.ruby-forum.com/.

Brian,
Thanks! I'll try some things out a let the forum know iff I produce
something of interest. Cheers, Andrew.

···

--
Posted via http://www.ruby-forum.com/.