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 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/.