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

A

Andrew Seidel

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

Brian Candler

Andrew said:
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.
 
A

Andrew Seidel

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

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top